[ZJOI2012]网络 解题报告

本文介绍了一种利用链剖分(LCT)解决动态链维护问题的方法,并对比了使用伸展树(Splay)的实现难度。通过具体实例讲解了LCT的基本操作,如旋转、获取路径等,并提供了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这题还是非常奇怪的,在考试的时候做了这题的弱化版,去了求最值。
这道题要求维护一坨链,显然是可以直接上splay的,所以我考试的时候直接写了splay,结果因为两个bug调了5个小时。
求最值的话,当然也可以直接上splay。。但是那样的话很麻烦,因为没法在端点加点,所以要很复杂的讨论。直接用lct的话就好很多,但是用lct维护一坨链实在是很奇怪。。
而且这题的数据很难生成,tm拍都没法拍。。我实在是懒了,就直接下了数据。我也不想为自己解释。
通过这题我发现我的代码能力急需提高啊。

#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
#include<algorithm>
#include<cmath>
const int N=1e4+5,M=1e5+5,C=10+5,K=1e5+5;
struct LS{
    int ch[2],fa;
    int v,max;
    bool flag;
}lct[N*C];
void out(int node){
    printf("%d:ch[0]=%d,ch[1]=%d,fa=%d,v=%d,max=%d\n",node,lct[node].ch[0],lct[node].ch[1],lct[node].fa,lct[node].v,lct[node].max);
}
void pushup(int node){
    lct[node].max=max(lct[node].v,max(lct[lct[node].ch[0]].max,lct[lct[node].ch[1]].max));
}
void paint(int node){
    if(node){
        lct[node].flag^=1;
        swap(lct[node].ch[0],lct[node].ch[1]);
    }
}
void pushdown(int node){
    if(lct[node].flag){
        //printf("pushdown ");
        //out(node);
        paint(lct[node].ch[0]),paint(lct[node].ch[1]);
        lct[node].flag=0;
    }
}
int stack[10005];
void down(int node){
    int top=0;
    for(;node;node=lct[node].fa)stack[top++]=node;
    while(top--)pushdown(stack[top]);
}
void rot(int node){
    int fa=lct[node].fa;
    bool dir=lct[fa].ch[1]==node;

    lct[node].fa=lct[fa].fa;
    lct[fa].fa=node;
    lct[lct[node].ch[!dir]].fa=fa;

    lct[fa].ch[dir]=lct[node].ch[!dir];
    lct[node].ch[!dir]=fa;
    if(lct[lct[node].fa].ch[0]==fa)lct[lct[node].fa].ch[0]=node;
    else if(lct[lct[node].fa].ch[1]==fa)lct[lct[node].fa].ch[1]=node;

    pushup(fa);
}
bool is_top(int node){
    return lct[node].fa==0||lct[lct[node].fa].ch[1]!=node&&lct[lct[node].fa].ch[0]!=node;
}
void splay(int node){
    down(node);
    for(int fa;!is_top(node);rot(node)){
        fa=lct[node].fa;
        if(!is_top(fa))
            if((lct[lct[fa].fa].ch[1]==fa)==(lct[fa].ch[1]==node))rot(fa);
            else rot(node);
    }
}
void discon(int node){
    splay(node);
    lct[node].ch[1]=0;
}
void access(int node){
    //printf("---access:%d---\n",node);
    for(discon(node);lct[node].fa;rot(node)){
        //printf("%d\n",node);
        discon(lct[node].fa);
        //cout<<lct[node].fa<<".ch[1]="<<node<<endl;
        lct[lct[node].fa].ch[1]=node;
    }
    pushup(node);
    //out(21),out(22);
}
void makeroot(int node){
    access(node);
    paint(node);
}
void getchain(int u,int v){
    makeroot(u);
    access(v);
}
void link(int from,int to){
    //printf("link:(%d->%d)\n",from,to);
    lct[from].fa=to;
}
void cut(int from,int to){
    //printf("cut:(%d->%d)\n",from,to);
    lct[from].fa=lct[to].ch[0]=0;
    pushup(to);
}

int deg[15][10005];

int n;
int cal(int w,int i){
    return w*n+i;
}
void in(int &x){
    char c=getchar();
    for(;c<'0'||c>'9';c=getchar());
    for(x=0;c>='0'&&c<='9';c=getchar())x=x*10+(c^'0');
}
int ptr[N*C],next[M<<1],succ[M<<1],etot=1;
void addedge(int from,int to){
    next[etot]=ptr[from],ptr[from]=etot,succ[etot++]=to;
}
int q[10005];
void bfs(int node){
    int h=0,t=1;
    q[0]=node;
    for(;h!=t;++h)
        for(int i=ptr[q[h]];i;i=next[i])
            if(succ[i]!=lct[q[h]].fa){
                lct[succ[i]].fa=q[h];
                //printf("fa(%d)=%d\n",succ[i],q[h]);
                q[t++]=succ[i];
            }
}
int main(){
    //freopen("bzoj_2816.in","r",stdin);
    //freopen("bzoj_2816.out","w",stdout);
    freopen("networkzj.in","r",stdin);
    freopen("networkzj.out","w",stdout);
    int m,c,k;
    in(n),in(m),in(c),in(k);
    for(int i=1;i<=n;++i){
        in(lct[i].v);
        for(int j=0,k=i;j<c;++j,k+=n)lct[k].v=lct[i].v;
    }
    for(int i=n*c;i;--i)lct[i].max=lct[i].v;
    int u,v,w;
    for(int i=m;i;--i){
        in(u),in(v),in(w);
        addedge(cal(w,u),cal(w,v)),addedge(cal(w,v),cal(w,u));
        ++deg[w][u],++deg[w][v];
    }
    for(int i=n*c;i;--i)
        if(!lct[i].fa)
            bfs(i);
    int opt,x,y,prew;
    for(;k;--k){
        //printf("----%d-----\n",k);
        in(opt);
        switch(opt){
            case 0:
                in(x),in(y);
                for(int i=0;i<c;++i,x+=n){
                    splay(x);
                    lct[x].v=lct[x].max=y;
                }
                break;
            case 1:
                in(u),in(v),in(w);
                for(x=u+n*(c-1),y=v+n*(c-1),prew=c-1;x>0;--prew,x-=n,y-=n){
                    getchain(x,y);
                    if(lct[x].fa==y&&!lct[x].ch[1])break;
                }
                //cout<<x<<" "<<y<<":"<<prew<<endl;
                if(x<=0)puts("No such edge.");
                else if(w==prew)puts("Success.");
                else if(deg[w][u]==2||deg[w][v]==2)puts("Error 1.");
                else{
                    getchain(cal(w,u),cal(w,v));
                    if(lct[cal(w,u)].fa)puts("Error 2.");
                    else{
                        puts("Success.");
                        cut(x,y);
                        --deg[prew][u],--deg[prew][v];

                        link(cal(w,u),cal(w,v));
                        ++deg[w][u],++deg[w][v];
                    }
                }
                break;
            case 2:
                in(w),in(u),in(v);
                getchain(cal(w,u),cal(w,v));
                if(u==v||lct[cal(w,u)].fa)printf("%d\n",lct[cal(w,v)].max);
                else puts("-1");
                break;
        }
    }
}

总结:
①改变一个点的孩子指针前要pushdown它。
②链必须从端点开始dfs才行。
③lct中判断(u,v)是否联通,可以先access(u),再access(v),(或者直接getchain(u,v))然后看lct[u].fa,但是注意有个bug是u==v。
④lct中判断(u,v)是否存在,可以先getchain(u,v),如果存在的话,u就会是v的左儿子且u没有儿子,所以就需要看lct[u].fa!=v和lct[u].ch[1].

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值