input | output |
---|---|
3 3 1 2 1 2 3 3 3 1 4 |
2 3 |
4 5 1 2 1 2 3 1 1 3 2 1 4 2 2 4 1 |
1 2 5 |
构建一棵树,是的最长边-最短边最小。
用动态树维护mst。更新最小距离。
动态树的建发:
对每个点建立一个结点。对每条边建立一个结点。加边<u,v>的时候,如果u,v在同一棵树上
把u,v,access到同一个splay中,找到边最小的结点x,cut(x,v),cut(x,u)
把u,v分别变成自己所在树的根,然后对于边建立点x,link(x,u),link(x,v)即可。
动态树要维护的是树中边的权值。
44case T了一天了。实在没办法,换一种方法做吧,下次回来做这题
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<set> using namespace std; #define maxn 400007 #define inf 1000000000 int cnt = 0; struct Node{ Node *fa,*ch[2]; bool root,rev; int val,mval; Node(){} Node* init(int v,Node *f){ fa = f; ch[0] = ch[1] = f; root = true; val = mval = v; rev = false; return this; } void update(){ mval = val; if(ch[0]->mval < mval) mval = ch[0]->mval; if(ch[1]->mval < mval) mval = ch[1]->mval; } void update_rev(){ if(val == inf + 10000000)return ; rev = !rev; swap(ch[0],ch[1]); } void pushdown(){ if(rev){ ch[0]->update_rev(); ch[1]->update_rev(); rev = false; } } void rotate(){ Node *f = fa, *ff = f->fa; int t = (f->ch[1] == this); if(f->root) root = true, f->root = false; else ff->ch[ff->ch[1] == f] = this; fa = ff; f->ch[t] = ch[t^1]; ch[t^1]->fa = f; ch[t^1] = f; f->fa = this; f->update(); } void push(){ if(!root) fa->push(); pushdown(); } void splay(){ push(); Node *f, *ff; while(!root){ f = fa,ff = f->fa; if(!f->root) if((ff->ch[1]==f)&&(f->ch[1] == this)) f->rotate(); else rotate(); rotate(); } update(); } }; Node pool[maxn]; Node *nil,*tree[maxn]; void init(){ cnt = 1; nil = tree[0] = pool; nil->val = nil -> mval = inf+10000000; } //将x到树根的路径并成一条path****** Node *access(Node *x){ Node *y = nil; while(x != nil){ x->splay(); x->ch[1]->root = true; (x->ch[1] = y)->root = false; x->update(); y = x; x = x->fa; } return y; } //将结点x变成树根****** void be_root(Node *x){ //cout<<x->val-inf<<endl; access(x); x->splay(); x->update_rev(); //update_rev(x); } //将x连接到结点f上****** void link(Node *x, Node *f){ be_root(x); x->fa = f; } //将x,y分离****** void cut(Node *x,Node *y){ be_root(x); access(x); y->splay(); y->fa = nil; } Node *findminNode(Node *x){ if(x->val <= x->ch[0]->mval && x->val <= x->ch[1]->mval) return x; if(x->ch[0]->mval < x->ch[1]->mval) return findminNode(x->ch[0]); return findminNode(x->ch[1]); } Node *findRoot(Node *x){ if(x->ch[0] == nil) return x; return findRoot(x->ch[0]); } struct Edge{ int u,v,w; Edge (){} int getn(){ int n = 0; char x; while(1){ x = getchar(); if(x == ' ' || x == '\n') return n; n = n*10+x-'0'; } } void init(){ u = getn(); v = getn(); w = getn(); } }; Edge edge[maxn]; int fa[100007]; int find(int u){ if(fa[u] == u) return u; return fa[u] = find(fa[u]); } multiset<int>haha; int comp1(int a,int b){ return edge[a].w < edge[b].w; } int id[100007]; int main(){ //freopen("j.in","r",stdin); //freopen("jl.out","w",stdout); int n,m; while(scanf("%d%d",&n,&m)!=EOF){ haha.clear(); //edge.clear(); Edge e; getchar(); for(int i = 0;i < m; i++){ edge[i].init(); if(edge[i].u == edge[i].v){ m--; i--; continue; } id[i] = i; } sort(id,id+m,comp1); init(); for(int i = 1;i <= n;i++) tree[i] = pool[cnt++].init(inf+i,nil); int num = n,ans=1000000000,be,en; Node *x,*y,*z; for(int i = 0;i < m; i++){ int u = edge[id[i]].u,v = edge[id[i]].v,w=edge[id[i]].w; haha.insert(w); z = pool[cnt++].init(w,nil); be_root(tree[u]); x = access(tree[v]); y = findRoot(x); if(tree[u] == y){ x = findminNode(x); cut(x,tree[u]); cut(x,tree[v]); haha.erase(haha.find(x->val)); num++; } link(tree[u],z); link(tree[v],z); num--; if(num == 1){ int mval = *haha.begin(); if(w - mval < ans){ ans = w - mval; be = mval; en = w; } } } num = n; for(int i = 0;i <= n; i++) fa[i] = i; for(int i = 0;i < m; i++){ e = edge[i]; if(e.w >= be && e.w <= en){ int f1 = find(e.u); int f2 = find(e.v); if(f1 != f2){ fa[f1] = fa[f2]; if(num != n) putchar(' '); printf("%d",i+1); num--; } } } printf("\n"); } return 0; }