P2486 [SDOI2011]染色 (树链剖分)

P2486 [SDOI2011]染色

分析:

颜色段数用线段树维护,记录最左端颜色与最右端颜色,每一次合并的时候,如果中间颜色有重叠,就将段数--。

链剖查询的时候注意两条链端点颜色相同的情况。

因为跳链是一个交替的过程,记录一下左右链跳完之后跳到的颜色是哪一种:ans1对应左边的x,ans2对应右边的y。

每一次x与y深度交换的时候,将ans1与ans2也交换,保证对应的关系。

#include<bits/stdc++.h>
using namespace std;
#define ri register int 
#define N 100005
#define mid ((l+r)>>1)
int Lc,Rc,lc[N*4],rc[N*4],sum[N*4],add[N*4],n;
int fa[N],siz[N],son[N],id[N],dfn[N],cnt=0,dep[N],col[N],topp[N];
vector<int> e[N];
void dfs1(int u,int ff)
{
    siz[u]=1;
    for(ri i=0;i<e[u].size();++i){
        int v=e[u][i];
        if(v==ff) continue; fa[v]=u;
        dep[v]=dep[u]+1; dfs1(v,u); siz[u]+=siz[v];
        if(siz[son[u]]<siz[v]) son[u]=v;
    }
}
void dfs2(int u,int tp)
{
    dfn[++cnt]=u; id[u]=cnt; topp[u]=tp;
    if(son[u]) dfs2(son[u],tp);
    for(ri i=0;i<e[u].size();++i){
        int v=e[u][i];
        if(v==fa[u] || v==son[u]) continue;
        dfs2(v,v);
    }
}
void update(int s)
{
    sum[s]=sum[s<<1]+sum[s<<1|1]-(rc[s<<1]==lc[s<<1|1]);
    lc[s]=lc[s<<1]; rc[s]=rc[s<<1|1];
}
void build(int s,int l,int r)
{
    if(l==r) { sum[s]=1; add[s]=0; lc[s]=rc[s]=col[dfn[l]]; return ; }
    build(s<<1,l,mid); build(s<<1|1,mid+1,r);
    update(s);
}
void pushdown(int s)
{
    if(!add[s]) return ;
    int v=add[s];
    add[s<<1]=add[s<<1|1]=lc[s<<1]=lc[s<<1|1]=rc[s<<1]=rc[s<<1|1]=v;
    sum[s<<1]=sum[s<<1|1]=1;
    add[s]=0;
}
void modify(int s,int l,int r,int L,int R,int v)
{
    if(L<=l && r<=R) { add[s]=v; sum[s]=1; lc[s]=rc[s]=v; return;  }
    pushdown(s);
    if(L<=mid) modify(s<<1,l,mid,L,R,v);
    if(R>mid)  modify(s<<1|1,mid+1,r,L,R,v);
    update(s);
}
int query(int s,int l,int r,int L,int R)
{
    if(l==L) Lc=lc[s]; if(r==R) Rc=rc[s];
    if(L<=l && r<=R) return sum[s];
    pushdown(s);
    int ans=0,fl=0;
    if(L<=mid) ans+=query(s<<1,l,mid,L,R),fl++;
    if(R>mid)  ans+=query(s<<1|1,mid+1,r,L,R),fl++;
    if(fl==2) ans-=(rc[s<<1]==lc[s<<1|1]);
    return ans;
}
void modify_link(int x,int y,int c)
{
    while(topp[x]!=topp[y]){
        if(dep[topp[x]]<dep[topp[y]]) swap(x,y);
        modify(1,1,n,id[topp[x]],id[x],c);
        x=fa[topp[x]];
    }
    if(dep[x]<dep[y]) swap(x,y);
    modify(1,1,n,id[y],id[x],c);
}
int query_link(int x,int y)
{
    int ans=0,ans1=-1,ans2=-1;
    while(topp[x]!=topp[y]){
        if(dep[topp[x]]<dep[topp[y]]) swap(x,y),swap(ans1,ans2);//x对应ans1 y对应ans2 
        ans+=query(1,1,n,id[topp[x]],id[x]);
        if(ans1==Rc) ans--;//Rc记录的是这一次链的下端 如果和上一次的上端颜色是一样的 就-- 
        ans1=Lc; x=fa[topp[x]];
    }
    if(dep[x]>dep[y]) swap(x,y),swap(ans1,ans2);//!!ans1一定是和x对应的 所以说如果下面要用ans1与Lc比较的话 要保证x在上方 
    ans+=query(1,1,n,id[x],id[y]);
    if(ans1==Lc) ans--;
    if(ans2==Rc) ans--;
    return ans;
}
int main()
{
    int a,b,c,m;
    scanf("%d%d",&n,&m);
    for(ri i=1;i<=n;++i) scanf("%d",&col[i]);
    for(ri i=1;i<=n-1;++i) scanf("%d%d",&a,&b),e[a].push_back(b),e[b].push_back(a);
    dep[1]=1; dfs1(1,0); dfs2(1,1);
    build(1,1,n);
    char op[2]; 
    for(ri i=1;i<=m;++i){
        scanf("%s%d%d",op,&a,&b);
        if(op[0]=='C') scanf("%d",&c),modify_link(a,b,c);
        else printf("%d\n",query_link(a,b));
    }
    return 0;
}
/*
6 100
2 2 1 2 1 1
1 2
1 3
2 4
2 5
2 6
Q 3 4
Q 1 5
Q 6 5
Q 6 4
C 1 4 1
Q 6 4


Q 3 5
C 2 1 1
Q 3 5
C 5 1 2
Q 3 5
*/
View Code

猜你喜欢

转载自www.cnblogs.com/mowanying/p/11823448.html