[BZOJ2049]洞穴勘测[BZOJ2157]旅游Link-Cut Tree模板题

来源:互联网 发布:开淘宝微店能赚钱吗 编辑:程序博客网 时间:2024/05/21 15:55

第一次写LCT,先来两道模板题,因为上个月被三道区间维护的超级工业的splay搞傻了,吸取了很多教训(见前几篇博客),所以LCT写得很顺啊,这里要感谢hzwer的题解。
BZOJ 2049:给出一颗树,每次加一条边或者删除一条边,询问两点的连通性。
这是一眼题,最裸的,纯天然的LCT,如果你不会先去看论文吧。半年以前看LCT感觉是一个非常高端的东西,当时反正看不懂,而TTY又有LCT爷的称号,写LCT都不用调,自然是伏地%。今天写了写发现还好。
废话不多说,查连通性就判断两个点的树的根是不是相等就可以了。

#include<ctime>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<iostream>#include<string>#include<cassert>#include<cmath>#include<vector>#include<queue>#include<stack>#include<map>#include<climits>#define X first#define Y second#define DB double#define MP make_pair#define LL long long#define pb push_back#define sqr(_) ((_)*(_))#define INF 0x3f3f3f3f#define pii pair<int,int>#define pdd pair<DB,DB>#define ull unsigned LL#define DEBUG(...) fprintf(stderr,__VA_ARGS__)using namespace std;void Read(int& x){    x=0;int flag=0;char c;    while(c=getchar())    {        if(c>='0'&&c<='9')x*=10,x+=c-'0',flag=1;        else if(flag)break;    }}const int MAXN=10010;int n,m;char s[10];struct Link_Cut_Tree{    int fa[MAXN],son[MAXN][2],rev[MAXN],top,st[MAXN];    Link_Cut_Tree(){        memset(fa,0,sizeof(fa));        memset(son,0,sizeof(son));        memset(rev,0,sizeof(rev));        top=0;    }    bool isroot(int x)    {        return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;    }    void rotate(int x)    {        int y=fa[x],d=(x==son[y][1]);        if(fa[y]&&!isroot(y))        {            son[fa[y]][son[fa[y]][1]==y]=x;        }        assert(x!=fa[y]);        fa[x]=fa[y];        assert(y!=x);        fa[y]=x;        son[y][d]=son[x][d^1];        if(son[x][d^1])fa[son[x][d^1]]=y;        son[x][d^1]=y;    }    void update_rev(int now)    {        rev[now]^=1;        swap(son[now][0],son[now][1]);    }    void push_down(int x)    {        if(rev[x])        {            rev[x]^=1;            update_rev(son[x][0]);            update_rev(son[x][1]);        }    }    void splay(int x)    {        st[++top]=x;        int tmp=x;        while(!isroot(tmp))        {            st[++top]=fa[tmp];            tmp=fa[tmp];        }        while(top)        {            push_down(st[top]);            top--;        }        while(!isroot(x))        {            int y=fa[x];            if(isroot(y))            {                rotate(x);                break;            }            rotate(x);        }    }    void aksess(int x)    {        int tmp=0;        while(x)        {            splay(x);            son[x][1]=tmp;            tmp=x;            x=fa[x];        }    }    void beroot(int x)    {        aksess(x);        splay(x);        update_rev(x);    }    void link(int x,int y)    {        beroot(x);        fa[x]=y;        splay(x);    }    void cut(int x,int y)    {        beroot(x);        aksess(y);        splay(y);        son[y][0]=fa[x]=0;    }    int find(int x)    {        aksess(x);        splay(x);        int tmp=x;        while(tmp)        {            if(!son[tmp][0])                return tmp;            tmp=son[tmp][0];        }    }}LCT;int main(){#ifndef ONLINE_JUDGE    freopen("cave.in","r",stdin);    freopen("cave.out","w",stdout);#endif    Read(n);Read(m);    for(int i=1;i<=m;i++)    {        scanf("%s",s);        if(s[0]=='Q')        {            int a,b;            Read(a);Read(b);            if(LCT.find(a)==LCT.find(b))                puts("Yes");            else                puts("No");        }        else if(s[0]=='D')        {            int a,b;            Read(a);Read(b);            LCT.cut(a,b);        }        else        {            int a,b;            Read(a);Read(b);            LCT.link(a,b);        }    }}

BZOJ 2157:给出一棵树,每次可以更改边权,路径边权置负,查询路径权值和,路径权值最大值,路径权值最小值。
虽然这一题既没有加边也没有删边,但是为了多A一道题而且能练习一下打改值标记的splay,就没有写树链剖分了。
LCT是不能维护边的权值的,我们考虑把边建成点,第i号边就是第n+i号点,然后也是模板题了。这里树上路径问题与区间维护问题有一点点不同,区间维护的splay要设两个虚点,取出区间就是把一个点splay到根,另一个点splay到根的右儿子,取出右儿子的子树。而LCT直接换根,aksess,再splay就可以了。

#include<ctime>#include<cstdio>#include<cstdlib>#include<cstring>#include<algorithm>#include<iostream>#include<string>#include<cassert>#include<cmath>#include<vector>#include<queue>#include<stack>#include<map>#include<climits>#define X first#define Y second#define DB double#define MP make_pair#define LL long long#define pb push_back#define lc son[now][0]#define rc son[now][1]#define sqr(_) ((_)*(_))#define INF 0x3f3f3f3f#define pii pair<int,int>#define pdd pair<DB,DB>#define ull unsigned LL#define DEBUG(...) fprintf(stderr,__VA_ARGS__)using namespace std;void Read(int& x){    x=0;int flag=0,sgn=1;char c;    while(c=getchar())    {        if(c=='-')sgn=-1;        else if(c>='0'&&c<='9')x*=10,x+=c-'0',flag=1;        else if(flag)break;    }    x*=sgn;}const int MAXN=200011;char s[10];int n,m,f[MAXN];struct Link_Cut_Tree{    int fa[MAXN],son[MAXN][2],st[MAXN],top,mx[MAXN],sum[MAXN],mn[MAXN],v[MAXN];    bool rev[MAXN],neg[MAXN];    Link_Cut_Tree(){        top=0;        memset(rev,0,sizeof(rev)); memset(neg,0,sizeof(neg));        memset(fa,0,sizeof(fa));   memset(son,0,sizeof(son));        memset(mx,-INF,sizeof(mx));memset(mn,INF,sizeof(mn));        memset(sum,0,sizeof(sum)); memset(v,0,sizeof(v));    }    void update_rev(int now)    {        rev[now]^=1;        swap(lc,rc);    }    void update_neg(int now)    {        neg[now]^=1;        sum[now]*=-1;        swap(mx[now],mn[now]);        mx[now]*=-1;        mn[now]*=-1;        v[now]*=-1;    }    void update(int now)    {        sum[now]=sum[lc]+sum[rc]+v[now];        mn[now]=min(mn[lc],mn[rc]);        mx[now]=max(mx[rc],mx[lc]);        if(now>n)        {            mn[now]=min(mn[now],v[now]);            mx[now]=max(mx[now],v[now]);        }    }    void push_down(int now)    {        if(rev[now])        {            rev[now]^=1;            update_rev(lc);            update_rev(rc);        }        if(neg[now])        {            neg[now]^=1;            update_neg(lc);            update_neg(rc);        }    }    bool isroot(int x)    {        return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;    }       void rotate(int x)    {        int y=fa[x],d=(son[y][1]==x);        if(fa[y]&&!isroot(y))            son[fa[y]][son[fa[y]][1]==y]=x;        fa[x]=fa[y];        fa[y]=x;        son[y][d]=son[x][d^1];        if(son[x][d^1])            fa[son[x][d^1]]=y;        son[x][d^1]=y;        update(y);update(x);    }    void splay(int x)    {        top=0;        st[++top]=x;        int tmp=x;        while(!isroot(tmp))        {            st[++top]=fa[tmp];            tmp=fa[tmp];        }        while(top)            push_down(st[top--]);        while(!isroot(x))            rotate(x);    }    void aksess(int x)    {        int t=0;        while(x)        {            splay(x);            son[x][1]=t;            update(x);            t=x;x=fa[x];        }    }    void beroot(int x)    {        aksess(x);        splay(x);        update_rev(x);    }    void link(int x,int y)    {        beroot(x);        fa[x]=y;        splay(x);    }    void split(int x,int y)    {        beroot(x);        aksess(y);        splay(y);    }}LCT;int main(){#ifndef ONLINE_JUDGE    freopen("tour.in","r",stdin);    freopen("tour.out","w",stdout);#endif    scanf("%d",&n);    int id=n;    for(int i=1;i<n;i++)    {        //DEBUG("%d\n",i);        int a,b,c;        scanf("%d %d %d",&a,&b,&c);        a++,b++;        LCT.v[++id]=c,LCT.update(id);//插节点注意update        f[i]=id;        LCT.link(a,id),LCT.link(b,id);    }    scanf("%d",&m);    for(int i=1;i<=m;i++)    {        scanf("%s",s);        int x,y;        Read(x),Read(y);        if(s[0]=='C')        {            LCT.splay(f[x]);            LCT.v[f[x]]=y;            LCT.update(f[x]);        }        else if(s[0]=='N')        {            LCT.split(x+1,y+1);            LCT.update_neg(y+1);        }        else if(s[0]=='S')        {            LCT.split(x+1,y+1);            printf("%d\n",LCT.sum[y+1]);        }        else if(s[1]=='A')        {            LCT.split(x+1,y+1);            printf("%d\n",LCT.mx[y+1]);        }        else        {            LCT.split(x+1,y+1);            printf("%d\n",LCT.mn[y+1]);        }    }}
0 0