4234最小差值生成树

匿名 (未验证) 提交于 2019-12-02 23:49:02

有点巧妙啊!

s[x]每次维护的是最小值

我们将边按从大到小排个序,这样编号小的就在前面啦!QAQ

再按最小生成树的LCT的做法来

不过我们每次要用一个book标记前面最小边的编号

每次要更新答案时,一直往前跳,跳到最晚更新的即使最小的

我口胡的,错了请dalao指出

#include<iostream> #include<cmath> #include<cstring> #include<cstdio> #include<algorithm> #define MN 700005 #define re register int #define ll long long using namespace std; int f[MN],v[MN],s[MN],r[MN],son[MN][2]; int zhan[MN]; int n,m,cnt; int book[MN]; int ltk; struct tu{     int u,v,w; }e[MN]; bool comp(tu p,tu q){     return p.w<q.w; } int get(int x){////判断节点是否为一个Splay的根(与普通Splay的区别1)     return son[f[x]][0]==x||son[f[x]][1]==x; }////如果连的是轻边,他的父亲的儿子里没有它 void pushup(int x){     s[x]=x;     if(s[son[x][0]]> n && (s[x]<= n ||s[x]>s[son[x][0]] ) ) s[x]=s[son[x][0]];     if(s[son[x][1]]> n && (s[x]<= n ||s[x]>s[son[x][1]] ) ) s[x]=s[son[x][1]]; } void filp(int x){     swap(son[x][0],son[x][1]);     r[x]^=1; } void pushdown(int x){     if(!r[x])return;     r[x]=0;     if(son[x][0])filp(son[x][0]);     if(son[x][1])filp(son[x][1]); } void rotate(int x){     int y=f[x],z=f[y],k=(son[y][1]==x),s=son[x][!k];     if(get(y))son[z][son[z][1]==y]=x;son[x][!k]=y;son[y][k]=s;     if(s)f[s]=y;f[y]=x;f[x]=z;     pushup(y); } void splay(int x){     int y=x,top=0;     zhan[++top]=y;     while(get(y))zhan[++top]=f[y],y=f[y];     while(top)pushdown(zhan[top--]);     while(get(x)){         y=f[x],top=f[y];         if(get(y))         rotate((son[y][0]==x)^(son[top][0]==y)?x:y);         rotate(x);     }     pushup(x);     return; } void access(int x){     for(re y=0;x;y=x,x=f[x]){     splay(x);     son[x][1]=y;     pushup(x);     } } void makeroot(int x){     access(x);     splay(x);     filp(x); } int findroot(int x){         access(x);     splay(x);     while(son[x][0])pushdown(x),x=son[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);     if(findroot(y)!=x)f[x]=y; } void cut(int x){ //对cut进行%改     splay(x);     f[son[x][0]]=f[son[x][1]]=0; } int main(){     scanf("%d%d",&n,&m);     int pos=1;     int ans=0x7fffffff;     int now=0;     for(re i=1;i<=m;i++)     {         scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);     }     sort(e+1,e+1+m,comp);     for(re i=1;i<=m;i++){         int x=e[i].u,y=e[i].v;         if(x==y){book[i]=1;continue;}         makeroot(x);         if(findroot(y)!=x)link(e[i].u,i+n),link(i+n,e[i].v),++ltk;         else{                     split(x,y);             now=s[y];             book[now-n]=1;             cut(now);             link(x,n+i);             link(n+i,y);         }         while(book[pos]&&pos<=i)++pos;         if(ltk>=n-1)ans=min(ans,e[i].w-e[pos].w); }     printf("%d\n",ans);     return 0; }

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!