洛谷 P2486 [SDOI2011]染色

题目描述

 

输入输出格式

输入格式:

  

输出格式:

 

对于每个询问操作,输出一行答案。

 

输入输出样例

输入样例#1:
6 5
2 2 1 2 1 1
1 2
1 3
2 4
2 5
2 6
Q 3 5
C 2 1 1
Q 3 5
C 5 1 2
Q 3 5
输出样例#1:
3
1
2

说明

题解:

树剖,用线段树维护:

数组tot[N]表示此时的颜色段数。

数组zzz[N]表示此时最左边的节点的颜色。

数组yyy[N]表示此时最右边的节点的颜色。

则: 首先我们要明确,线段树的叶子节点一定只有一种颜色,也就是一条颜色段。

tot[父亲]=tot[左儿子]+tot[右儿子];

if (zzz[右儿子]==yyy[左儿子]) {tot[父亲]--;}

即如果右儿子的最左边颜色和左儿子的最右边颜色相同,那么肯定有中间部分属于同一颜色段。

代码:

#include <cstdio>
    #include <cstring>
    #include <iostream>
    #define k (z+y>>1)
    #define ll (r<<1)
    #define rr (r<<1|1)
    using namespace std;
    const int N=1e5+10;int a[N];
    int ys[N],s[N*2][2],o[N],cnt,dfn,n;
    int zzz[N*4],yyy[N*4],laz[N*4],tot[N*4];
    int d[N],siz[N],son[N],top[N],f[N],id[N];
    void jia(int a,int b)
    {
        s[++cnt][1]=o[a];
        s[cnt][0]=b;o[a]=cnt;
        return;
    }
    void shang(int r)
    {
        tot[r]=tot[ll]+tot[rr];
        zzz[r]=zzz[ll];yyy[r]=yyy[rr];
        if (zzz[rr]==yyy[ll]) tot[r]--;
        return;
    }
    void xiangxia(int r,int z,int y)
    {
        tot[ll]=tot[rr]=1;
        zzz[ll]=zzz[rr]=yyy[ll]=yyy[rr]=laz[ll]=laz[rr]=laz[r];
        laz[r]=0;return;
    }
    void jianshu(int r,int z,int y)
    {
        if (z==y) {
            tot[r]=1;zzz[r]=yyy[r]=ys[a[z]];
            return;
        }
        jianshu(ll,z,k);jianshu(rr,k+1,y);
        shang(r);return;
    }
    void gai(int r,int z,int y,int zz,int yy,int v)
    {
        if (z==zz&&y==yy) {
            tot[r]=1;laz[r]=zzz[r]=yyy[r]=v;
            return;
        }
        if (laz[r]) xiangxia(r,z,y);
        if (zz>k) gai(rr,k+1,y,zz,yy,v);
        else if (yy<=k) gai(ll,z,k,zz,yy,v);
        else {gai(ll,z,k,zz,k,v);gai(rr,k+1,y,k+1,yy,v);}
        shang(r);return;
    }
    int chaxun(int r,int z,int y,int zz,int yy)
    {
        if (z==zz&&y==yy) return tot[r];
        if (laz[r]) xiangxia(r,z,y);
        if (zz>k) chaxun(rr,k+1,y,zz,yy);
        else if (yy<=k) chaxun(ll,z,k,zz,yy);
        else {
            int ans=chaxun(ll,z,k,zz,k)+chaxun(rr,k+1,y,k+1,yy);
            if (zzz[rr]==yyy[ll]) ans--;
            return ans;
        }
    }
    void dfs1(int x,int fa,int dep)
    {
        f[x]=fa;d[x]=dep;siz[x]=1;
        for (int i=o[x];i;i=s[i][1]) {
            if (s[i][0]!=fa) {
                dfs1(s[i][0],x,dep+1);
                siz[x]+=siz[s[i][0]];
                if (siz[s[i][0]]>siz[son[x]]) son[x]=s[i][0];
            }
        }
        return;
    }
    void dfs2(int x,int tp)
    {
        top[x]=tp;id[x]=++dfn;a[dfn]=x;
        if (son[x]) dfs2(son[x],tp);
        for (int i=o[x];i;i=s[i][1])
        if (s[i][0]!=f[x]&&son[x]!=s[i][0])
        dfs2(s[i][0],s[i][0]);
        return;
    }
    void ranse(int x,int y,int v)
    {
        while (top[x]!=top[y]) {
            if (d[top[x]]>d[top[y]]) swap(x,y);
            gai(1,1,n,id[top[y]],id[y],v);
            y=f[top[y]];
        }
        if (d[x]>d[y]) swap(x,y);
        gai(1,1,n,id[x],id[y],v);
        return;
    }
    int newww(int r,int z,int y,int p)
    {
        if (z==y) return zzz[r];
        if (laz[r]) xiangxia(r,z,y);
        if (p>k) return newww(rr,k+1,y,p);
        else return newww(ll,z,k,p);
    }
    int xunwen(int x,int y)
    {
        int ans=0,nc,fc;
        while (top[x]!=top[y]) {
            if (d[top[x]]>d[top[y]]) swap(x,y);
            ans+=chaxun(1,1,n,id[top[y]],id[y]);
            nc=newww(1,1,n,id[top[y]]);
            fc=newww(1,1,n,id[f[top[y]]]);
            y=f[top[y]];if (nc==fc) ans--;
        }
        if (d[x]>d[y]) swap(x,y);
        ans+=chaxun(1,1,n,id[x],id[y]);
        return ans?ans:1;
    }
    int main()
    {
        int m,a,b,c;
        cin>>n>>m;char caozuo[5];
        for (int i=1;i<=n;i++) scanf("%d",&ys[i]);
        for (int i=1;i<n;i++) {
            scanf("%d%d",&a,&b);jia(a,b);jia(b,a);
        }
        dfs1(1,0,1);dfs2(1,1);jianshu(1,1,n);
        while (m--) {
            scanf("%s",caozuo);
            scanf("%d%d",&a,&b);
            switch (caozuo[0]) {
                case 'C':scanf("%d",&c);
                ranse(a,b,c);break;
         default:

                printf("%d\n",xunwen(a,b));break;
            }
        }
        //zhu wo zao dian AC!!!
        return 0;
    }

ok!!!

 

posted @ 2018-01-14 09:12  fuyan0101  阅读(280)  评论(0编辑  收藏  举报