• [BZOJ2243][SDOI2011]染色


    2243: [SDOI2011]染色

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 10933  Solved: 4237
    [Submit][Status][Discuss]

    Description

    给定一棵有n个节点的无根树和m个操作,操作有2类:
    1、将节点a到节点b路径上所有点都染成颜色c;
    2、询问节点a到节点b路径上的颜色段数量(连续相同颜色被认为是同一段),
    如“112221”由3段组成:“11”、“222”和“1”。
    请你写一个程序依次完成这m个操作。

    Input

    第一行包含2个整数n和m,分别表示节点数和操作数;
    第二行包含n个正整数表示n个节点的初始颜色
    下面 行每行包含两个整数x和y,表示x和y之间有一条无向边。
    下面 行每行描述一个操作:
    “C a b c”表示这是一个染色操作,把节点a到节点b路径上所有点(包括a和b)都染成颜色c;
    “Q a b”表示这是一个询问操作,询问节点a到节点b(包括a和b)路径上的颜色段数量。

    Output

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

     

    Sample Input

    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

    Sample Output

    3
    1
    2

    HINT

    数N<=10^5,操作数M<=10^5,所有的颜色C为整数且在[0, 10^9]之间。

    Source

    试题分析

    毒瘤题目,$A$掉了是真的开心啊!!!

    建立线段树

    其实做法十分显然,我们考虑树链剖分,对于线段树上我们维护在$[l,r]$区间内的颜色段$(ans(k))$,而要求$ans(k)$我们需要左右节点的$ans,ans(k<<1),ans(k<<1|1)$,并且我们需要判断合并时若$mid$与$mid+1$同颜色便需要$-1$,而对于任意都$ans(k)=ans(k<<1)+ans(k<<1|1)$。

    在路径上覆盖颜色(即$1$操作)

    考虑线段树覆盖颜色,记录一下次条线段是否被覆盖。

    查询颜色数量(即$2$操作)

    我们在建立线段树时已经讨论了$-1$的问题,而$-1$在树上维护时我们需要去求当现在要求$(u,v)$,$(deep(u)<deep(v))$时,我们需要查询路径中有没有$v$的儿子,有的话判断两个点的颜色是否相同,若相同就$-1$.

    然后就慢慢垒吧。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int N=500001;
    struct node{
        int u,v,nex;
    }x[N<<1];
    int val[N],deep[N],fa[N],m,size[N],son[N],top[N],head[N],cnt,seg[N],id[N],n;
    void add(int u,int v){
        x[cnt].u=u,x[cnt].v=v,x[cnt].nex=head[u],head[u]=cnt++;
    }
    void dfs1(int f,int fath){
        size[f]=1;
        deep[f]=deep[fath]+1;
        fa[f]=fath;
        for(int i=head[f];i!=-1;i=x[i].nex){
            if(x[i].v==fath) continue;
            dfs1(x[i].v,f);
            size[f]+=size[x[i].v];
            if(size[son[f]]<size[x[i].v]) son[f]=x[i].v;
        }return;
    }
    void dfs2(int f,int fath){
        if(son[f]){
            top[son[f]]=top[f];
            seg[son[f]]=++seg[0];
            id[seg[0]]=son[f];
            dfs2(son[f],f);
        }
        for(int i=head[f];i!=-1;i=x[i].nex){
            if(x[i].v==fath||x[i].v==son[f]) continue;
            seg[x[i].v]=++seg[0];
            id[seg[0]]=x[i].v;
            top[x[i].v]=x[i].v;
            dfs2(x[i].v,f);
        }
    }
    int ans[N<<2],flag[N];
    int lst,Ans;
    struct segment_tree{
        void pushdown(int k,int l,int r){
            if(flag[k]==-1) return;
            int mid=l+r>>1;
            ans[k<<1]=1;ans[k<<1|1]=1;
            flag[k<<1]=flag[k],flag[k<<1|1]=flag[k];
            int color=flag[k];
            val[id[l]]=color,val[id[mid]]=color,val[id[mid+1]]=color,val[id[r]]=color;
            flag[k]=-1;
            return;
        }
        void build(int k,int l,int r){
            if(l==r){ans[k]=1;return;}
            int mid=l+r>>1;
            build(k<<1,l,mid),build(k<<1|1,mid+1,r);
            ans[k]=ans[k<<1]+ans[k<<1|1];
            if(val[id[mid]]==val[id[mid+1]]) ans[k]--;
            return;
        }
        void change(int k,int l,int r,int x,int y,int col){
            if(x<=l&&r<=y){flag[k]=col;ans[k]=1;val[id[l]]=col,val[id[r]]=col;return;}
            int mid=l+r>>1;
            pushdown(k,l,r);
            if(x<=mid) change(k<<1,l,mid,x,y,col);
            if(mid<y) change(k<<1|1,mid+1,r,x,y,col);
            ans[k]=ans[k<<1]+ans[k<<1|1];
            if(val[id[mid]]==val[id[mid+1]]) ans[k]--;
            return;
        }
        int query_color(int k,int l,int r,int x,int y){
            if(l==r) return val[id[l]];
            pushdown(k,l,r);
            int mid=l+r>>1,res=0;
            if(x<=mid) res+=query_color(k<<1,l,mid,x,y);
            if(mid<y) res+=query_color(k<<1|1,mid+1,r,x,y);
            ans[k]=ans[k<<1]+ans[k<<1|1];
            if(val[id[mid]]==val[id[mid+1]]) ans[k]--;
            return res;
        }
        void query(int k,int l,int r,int x,int y){
            if(x<=l&&r<=y){
                Ans+=ans[k];
                if(lst!=-1)
                    if(query_color(1,1,n,lst,lst)==query_color(1,1,n,l,l)) Ans--;
                lst=r;
                return;
            }
            pushdown(k,l,r);
            int mid=l+r>>1;
            if(x<=mid) query(k<<1,l,mid,x,y);
            if(mid<y) query(k<<1|1,mid+1,r,x,y);
        }
        int Query(int x,int y){
            Ans=0;
            lst=-1;
            query(1,1,n,seg[x],seg[y]);
            return Ans;
        }
    }segment;
    char str[3];
    void change(int x,int y,int color){
        int fx=top[x],fy=top[y];
        while(fx!=fy){
            if(deep[fx]<deep[fy]) swap(x,y),swap(fx,fy);
            segment.change(1,1,seg[0],seg[fx],seg[x],color);
            x=fa[fx],fx=top[x];
        }
        if(deep[x]>deep[y]) swap(x,y);
        segment.change(1,1,seg[0],seg[x],seg[y],color);
        return;
    }
    int find(int x,int sonx,int sony){
        if(sonx==-1&&sony==-1) return 0;
        if(sonx==-1){
            if(fa[sony]==x) return sony;
            return 0;
        }
        if(sony==-1){
            if(fa[sonx]==x) return sonx;
            return 0;
        }
        if(fa[sonx]==x) return sonx;
        if(fa[sony]==x) return sony;
        return 0;
    }
    int query(int x,int y){
        int ans=0,fx=top[x],fy=top[y],sonx=-1,sony=-1;
        int tot=0;
        while(fx!=fy){
            ++tot;
            if(deep[fx]<deep[fy]) swap(x,y),swap(fx,fy);
            ans+=segment.Query(fx,x);
            int k=find(x,sonx,sony);
            if(k){
                int col1=segment.query_color(1,1,seg[0],seg[x],seg[x]);
                int col2=segment.query_color(1,1,seg[0],seg[k],seg[k]);
                if(col1==col2) ans--;
                if(sonx==k) sonx=fx;
                else sony=fx;
            }else{
                if(sonx==-1) sonx=fx;
                else sony=fx;
            }
            x=fa[fx],fx=top[x];
        }
        if(deep[x]>deep[y]) swap(x,y);
        int k1=find(x,sonx,sony);
        int k2=0;
        if(x!=y||(sonx!=-1&&sony!=-1&&sonx!=sony)) k2=find(y,sony,sonx);
        if(k1){
            if(sonx==k1) k1=sonx;
            else k1=sony;
        }
        if(k2){
            if(sonx==k2) k2=sonx;
            else k2=sony;
        }
        ans+=segment.Query(x,y);
        if(k1){
            int col1=segment.query_color(1,1,seg[0],seg[x],seg[x]);
            int col2=segment.query_color(1,1,seg[0],seg[k1],seg[k1]);
            if(col1==col2) ans--;
        }
        if(k2){
            int col1=segment.query_color(1,1,seg[0],seg[y],seg[y]);
            int col2=segment.query_color(1,1,seg[0],seg[k2],seg[k2]);
            if(col1==col2) ans--;
        }return ans;
    }
    int main(){
        memset(flag,-1,sizeof(flag));
        memset(head,-1,sizeof(head));
        n=read(),m=read();
        for(int i=1;i<=n;i++) val[i]=read();
        for(int i=1;i<n;i++){
            int u=read(),v=read();
            add(u,v),add(v,u);
        }
        dfs1(1,0);
        seg[0]=seg[1]=id[1]=top[1]=1;
        dfs2(1,0);
        segment.build(1,1,n);
        for(int i=1;i<=m;i++){
            scanf("%s",str+1);
            if(str[1]=='C'){
                int x=read(),y=read(),col=read();
                change(x,y,col);
            }else{
                int x=read(),y=read();
                printf("%d
    ",query(x,y));
            }
        }
        return 0;
    }
    
    View Code
  • 相关阅读:
    自定义博客园skin
    c++11: <thread>学习
    《明日方舟》Python版公开招募工具
    Python列表
    Python基础
    C#常用修饰符
    C#单例类的实现
    云服务器反黑客入侵攻防实录(一)
    在CentOS7.6上安装自动化运维工具Ansible以及playbook案例实操
    技术漫谈 | 远程访问和控制云端K8S服务器的方法
  • 原文地址:https://www.cnblogs.com/si-rui-yang/p/10222523.html
Copyright © 2020-2023  润新知