[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\n",query(x,y));
        }
    }
    return 0;
}
View Code

 

posted @ 2019-01-04 21:10  siruiyang_sry  阅读(182)  评论(0编辑  收藏  举报