[BZOJ2049]洞穴勘測[BZOJ2157]旅遊Link-Cut Tree模板題

第一次寫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]);
        }
    }
}
發佈了99 篇原創文章 · 獲贊 1 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章