bzoj2594 [Wc2006]水管局长数据加强版——LCT

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2594

时间倒序一下,就是 魔法森林 那道题;

有个不解的地方,是 access 里面关于 pushup 的地方,两种写法都可以,但不明白没有注释掉的写法为什么也可以。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int const maxn=1500005,maxm=1e6+5;
int n,m,Q,val[maxn],mx[maxn],fa[maxn],pre[maxn],c[maxn][3],sta[maxn],rev[maxn];
struct N{int hd,to,w,id; bool b;}edge[maxm];
struct T{int u,v,ans,f,id;}q[100005];
bool cmp(N x,N y){return x.w<y.w;}
bool cmp2(N x,N y){return x.hd<y.hd || (x.hd==y.hd && x.to<y.to);}
bool cmpp(N x,N y){return x.id<y.id;}
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
int rd()
{
    int ret=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
    while(ch>='0'&&ch<='9')ret=ret*10+ch-'0',ch=getchar();
    return ret*f;
}
int get(int x,int y)
{
    int l=1,r=m;
    while(l<=r)
    {
        int mid=((l+r)>>1);
        if(edge[mid].hd==x && edge[mid].to==y)return mid;
        if(edge[mid].hd<x || (edge[mid].hd==x && edge[mid].to<y))l=mid+1;
        else r=mid-1;
    }
}
bool isroot(int x)
{
    return c[pre[x]][0]!=x && c[pre[x]][1]!=x;
}
void pushup(int x)
{
    int ls=c[x][0],rs=c[x][1];
    mx[x]=x;
    if(val[mx[ls]]>val[mx[x]])mx[x]=mx[ls];
    if(val[mx[rs]]>val[mx[x]])mx[x]=mx[rs];
}
void reverse(int x)
{
    int ls=c[x][0],rs=c[x][1];
    if(rev[x])
    {
        rev[ls]^=1; rev[rs]^=1; rev[x]=0;
        swap(c[x][0],c[x][1]);
    }
}
void rotate(int x)
{
    int y=pre[x],z=pre[y],d=(c[y][1]==x);
    if(!isroot(y))c[z][c[z][1]==y]=x;
    pre[x]=z; pre[y]=x; pre[c[x][!d]]=y;
    c[y][d]=c[x][!d]; c[x][!d]=y;
    pushup(y); pushup(x);
}
void splay(int x)
{
    int top=0; sta[++top]=x;
    for(int i=x;!isroot(i);i=pre[i])sta[++top]=pre[i];
    for(int i=top;i;i--)reverse(sta[i]);
    for(;!isroot(x);rotate(x))
    {
        int y=pre[x],z=pre[y];
        if(isroot(y))continue;
        ((c[y][0]==x)^(c[z][0]==y))?rotate(x):rotate(y);
    }
    pushup(x);//和下面配套 
}
void access(int x)
{
    for(int t=0;x;c[x][1]=t,t=x,x=pre[x])splay(x);//这样为什么也可以? 
}
//void access(int x)
//{
//    int t=0;
//    while(x)
//    {
//        splay(x);c[x][1]=t;pushup(x);t=x;x=pre[x];
//    }
//}
void makeroot(int x)
{
    access(x); splay(x); rev[x]^=1;
}
void link(int x,int y)
{
    makeroot(x); pre[x]=y;//
}
void cut(int x,int y)
{
    makeroot(x); access(y); splay(y);
    pre[x]=0; c[y][0]=0;
}
int query(int x,int y)
{
    makeroot(x); access(y); splay(y); return mx[y];
}
int main()
{
    n=rd(); m=rd(); Q=rd();
    for(int i=1;i<=n;i++)fa[i]=i;
    for(int i=1;i<=m;i++)
    {
        edge[i].hd=rd(); edge[i].to=rd(); edge[i].w=rd();
        if(edge[i].hd>edge[i].to)swap(edge[i].hd,edge[i].to);
    }
    sort(edge+1,edge+m+1,cmp);//w 
    for(int i=1;i<=m;i++)
    {
        edge[i].id=i;
        val[i+n]=edge[i].w; mx[i+n]=i+n;//
    }
    sort(edge+1,edge+m+1,cmp2);//u,v 
    for(int i=1;i<=Q;i++)
    {
        q[i].f=rd(); q[i].u=rd(); q[i].v=rd();
        if(q[i].f==2)
        {
            if(q[i].u>q[i].v)swap(q[i].u,q[i].v);
            int t=get(q[i].u,q[i].v);
//            edge[t].b=1; q[i].id=edge[i].id;
            edge[t].b=1; q[i].id=edge[t].id;
        }
    }
    sort(edge+1,edge+m+1,cmpp);//w
    for(int i=1,tot=0;i<=m;i++)
    {
        if(edge[i].b)continue;//kruskal 连不删的边 
        int u=edge[i].hd,v=edge[i].to;
        if(find(u)!=find(v))
        {
            fa[find(u)]=find(v);
            link(u,i+n); link(v,i+n);
            tot++;
            if(tot==n-1)break;
        }
    }
    for(int i=Q;i;i--)
    {
        int u=q[i].u,v=q[i].v;
        if(q[i].f==1)q[i].ans=val[query(u,v)];
        else
        {
            int k=q[i].id,t=query(u,v);
            if(edge[k].w<val[t])
            {
                cut(t,edge[t-n].hd); cut(t,edge[t-n].to);
                link(u,k+n); link(v,k+n);
            }
        }
    }
    for(int i=1;i<=Q;i++)
        if(q[i].f==1)printf("%d\n",q[i].ans);
    return 0;
}

 

posted @ 2018-06-28 18:24  Zinn  阅读(160)  评论(0编辑  收藏  举报