bzoj2243 染色

维护一个区间里的颜色段个数,左端点颜色,右端点颜色和修改标记。

对于区间[a,b]和[b+1,c],它们的颜色段个数分别为x,y,如果b颜色和b+1颜色相同,那么[a,c]颜色段个数为x+y-1,否则为x+y。

树上深度浅的点dfs序要小一些。一个区间左端点就对应树上深度小的一个点,右端点对应树上深度大一些的一个点,。

跳重链时,用一个数记录上次跳的链的左端点,和当前所在链的右端点比较。

两个点跳到同一条重链上的时候,路径的两个端点都要判一下。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
char op[10];
int n,m,a,b,c;
int t[maxn],dfn[maxn],tot;
int col[maxn],son[maxn],fa[maxn],sz[maxn],dep[maxn],top[maxn];
int cnt=0,Head[maxn],Next[maxn<<1],V[maxn<<1];
struct node{
    int cl,cr;
    int cov,num;
    node(){cov=-1;}
}T[maxn<<2];
int read(){
    int x=0;char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return x;
}
void print(int x){
    if(x>9) print(x/10);
    putchar(x%10+'0');
}
void add(int u,int v){++cnt,Next[cnt]=Head[u],V[cnt]=v,Head[u]=cnt;}
void dfs1(int u,int f){
    sz[u]=1,son[u]=0;
    for(int i=Head[u];i;i=Next[i]){
        if(V[i]==f) continue;
        dep[V[i]]=dep[u]+1,fa[V[i]]=u;
        dfs1(V[i],u),sz[u]+=sz[V[i]];
        if(sz[son[u]]<sz[V[i]]) son[u]=V[i];
    }
}
void dfs2(int u,int tp){
    top[u]=tp,dfn[u]=++tot,t[tot]=u;
    if(son[u]) dfs2(son[u],tp);
    for(int i=Head[u];i;i=Next[i])
        if(V[i]!=fa[u]&&V[i]!=son[u])
            dfs2(V[i],V[i]);
}
node pushup(node Tl,node Tr){
    node ret;
    ret.num=Tl.num+Tr.num-(Tl.cr==Tr.cl);
    ret.cl=Tl.cl,ret.cr=Tr.cr;
    return ret;
}
void pushnow(int root,int val){T[root].cl=T[root].cr=T[root].cov=val,T[root].num=1;}
void pushdown(int root){
    if(T[root].cov==-1) return;
    pushnow(root<<1,T[root].cov),pushnow(root<<1|1,T[root].cov);
    T[root].cov=-1;
}
void build(int root,int l,int r){
    if(l==r){T[root].cl=T[root].cr=col[t[l]],T[root].num=1;return;}
    int mid=(l+r)>>1;
    build(root<<1,l,mid),build(root<<1|1,mid+1,r);
    T[root]=pushup(T[root<<1],T[root<<1|1]);
}
node query(int root,int l,int r,int x,int y){
    if(l>=x&&r<=y) return T[root];
    pushdown(root);
    int mid=(l+r)>>1;
    if(y<=mid) return query(root<<1,l,mid,x,y);
    if(x>mid)  return query(root<<1|1,mid+1,r,x,y);
    return pushup(query(root<<1,l,mid,x,y),query(root<<1|1,mid+1,r,x,y));
}
void change(int root,int l,int r,int x,int y,int val){
    if(l>=x&&r<=y){
        pushnow(root,val);
        return;
    }
    pushdown(root);
    int mid=(l+r)>>1;
    if(x<=mid) change(root<<1,l,mid,x,y,val);
    if(y>mid) change(root<<1|1,mid+1,r,x,y,val);
    T[root]=pushup(T[root<<1],T[root<<1|1]);
}
int ask(int x,int y){
    int ans=0,xl=0,yl=0;
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y),swap(xl,yl);
        node now=query(1,1,n,dfn[top[x]],dfn[x]);
        ans=ans+now.num-(now.cr==xl);
        xl=now.cl,x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y),swap(xl,yl);
    node now=query(1,1,n,dfn[x],dfn[y]);
    ans=ans+now.num-(xl==now.cl)-(yl==now.cr);
    return ans;
}
void modify(int x,int y,int val){
    while(top[x]!=top[y]){
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        change(1,1,n,dfn[top[x]],dfn[x],val);
        x=fa[top[x]];
    }
    if(dep[x]>dep[y]) swap(x,y);
    change(1,1,n,dfn[x],dfn[y],val);
}
int main(){
    n=read(),m=read();
    for(int i=1;i<=n;++i) col[i]=read();
    for(int i=1;i<n;++i) a=read(),b=read(),add(a,b),add(b,a);
    dfs1(1,0),dfs2(1,1),build(1,1,n);
    while(m--){
        scanf("%s",op);
        if(op[0]=='Q'){
            a=read(),b=read();
            print(ask(a,b)),putchar('\n');
        }
        if(op[0]=='C'){
            a=read(),b=read(),c=read();
            modify(a,b,c);
        }
    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值