1. 程式人生 > >luogu2387 [NOI2014]魔法森林

luogu2387 [NOI2014]魔法森林

魔法森林 play line link make access void source ans

這題和水管局長很像,枚舉 \(a\) 的邊然後維護關於 \(b\) 的最小生成樹就可以了。
1A吶>_<

#include <algorithm>
#include <iostream>
#include <cstdio>
using namespace std;
int n, m, val[150005], zdz[150005], ans=0x3f3f3f3f, fa[150005];
int ch[150005][2], rev[150005];
struct Edge{
    int fro, too, vaa, vab;
}edge[100005];
bool cmp(Edge x, Edge y){
    return
x.vaa<y.vaa; } void upd(int x){ zdz[x] = val[x]; if(edge[zdz[ch[x][0]]].vab>edge[zdz[x]].vab) zdz[x] = zdz[ch[x][0]]; if(edge[zdz[ch[x][1]]].vab>edge[zdz[x]].vab) zdz[x] = zdz[ch[x][1]]; } int getw(int x){ return ch[fa[x]][1]==x; } bool isroot(int x){ return
ch[fa[x]][0]!=x && ch[fa[x]][1]!=x; } void pushdown(int x){ if(rev[x]){ swap(ch[x][0], ch[x][1]); rev[ch[x][0]] ^= 1; rev[ch[x][1]] ^= 1; rev[x] = false; } } void xf(int x){ if(fa[x]) xf(fa[x]); pushdown(x); } void rotate(int x){ int old=fa[x], oldf=fa[old], w=getw(x); if
(!isroot(old)) ch[oldf][ch[oldf][1]==old] = x; ch[old][w] = ch[x][w^1]; ch[x][w^1] = old; fa[ch[old][w]] = old; fa[ch[x][w^1]] = x; fa[x] = oldf; upd(old); upd(x); } void splay(int x){ xf(x); while(!isroot(x)){ int f=fa[x]; if(!isroot(f)) rotate(getw(f)==getw(x)?f:x); rotate(x); } upd(x); } void access(int x){ int y=0; while(x){ splay(x); ch[x][1] = y; upd(x); y = x; x = fa[x]; } } void makeroot(int x){ access(x); splay(x); rev[x] ^= 1; } int findroot(int x){ access(x); splay(x); while(ch[x][0]) x = ch[x][0]; splay(x); return x; } void split(int x, int y){ makeroot(x); access(y); splay(y); } void link(int x, int y){ makeroot(x); fa[x] = y; } void cut(int x, int y){ split(x, y); fa[x] = ch[y][0] = 0; } int main(){ cin>>n>>m; for(int i=1; i<=m; i++){ scanf("%d %d %d %d", &edge[i].fro, &edge[i].too, &edge[i].vaa, &edge[i].vab); if(edge[i].fro>edge[i].too) swap(edge[i].fro, edge[i].too); } for(int i=n+1; i<=n+m; i++) val[i] = zdz[i] = i - n; sort(edge+1, edge+1+m, cmp); int j=1; for(int i=1; i<=50000; i++){ for(; j<=m && edge[j].vaa<=i; j++){ int x=edge[j].fro, y=edge[j].too; if(findroot(x)!=findroot(y)){ link(x, j+n); link(y, j+n); } else{ split(x, y); int idx=zdz[y]; if(edge[j].vab<edge[idx].vab){ cut(edge[idx].fro, idx+n); cut(edge[idx].too, idx+n); link(edge[j].fro, j+n); link(edge[j].too, j+n); } } } if(findroot(1)==findroot(n)){ split(1, n); ans = min(ans, i+edge[zdz[n]].vab); } } if(ans!=0x3f3f3f3f) printf("%d\n", ans); else printf("%d\n", -1); return 0; }

luogu2387 [NOI2014]魔法森林