[SDOI2011]染色

Description:

Hint:

\(n \le 10^5\)

Solution:

掌握了线段树区间合并的套路,这题就很简单了,树剖之后用线段树维护左右颜色,和区间颜色段数,查询跳链时分类讨论一下中间的颜色是否相同,修改直接修改就行了,代码稍有细节

#include<bits/stdc++.h>
#define ls p<<1
#define rs p<<1|1
using namespace std;
const int mxn=1e6+5;
int n,m,tot,cnt;
int a[mxn],v[mxn<<2],f[mxn],hd[mxn],lc[mxn],rc[mxn],sz[mxn],rk[mxn];
int dfn[mxn],top[mxn],son[mxn],coll[2],colr[2],dep[mxn],tag[mxn<<2];

struct ed {
    int to,nxt;
}t[mxn<<1];

inline void add(int u,int v) {
    t[++cnt]=(ed) {v,hd[u]}; hd[u]=cnt;
};

void push_up(int p)
{
    lc[p]=lc[ls]; rc[p]=rc[rs]; v[p]=v[ls]+v[rs];
    if(rc[ls]==lc[rs]) --v[p];
}

void push_down(int p)
{
    if(tag[p]) {
        tag[ls]=tag[rs]=tag[p];
        v[ls]=v[rs]=1;
        lc[ls]=lc[rs]=rc[ls]=rc[rs]=tag[p];
        tag[p]=0;
    }
}

void build(int l,int r,int p)
{
    if(l==r) {
        v[p]=1; lc[p]=rc[p]=a[rk[l]];
        return ;
    }
    int mid=(l+r)>>1;
    build(l,mid,ls);
    build(mid+1,r,rs);
    push_up(p);
}

void dfs1(int u,int fa)
{
    f[u]=fa; sz[u]=1; dep[u]=dep[fa]+1;
    for(int i=hd[u];i;i=t[i].nxt) {
        int v=t[i].to;
        if(v==fa) continue ;
        dfs1(v,u);
        sz[u]+=sz[v];
        if(sz[v]>sz[son[u]]) son[u]=v;
    }
}

void dfs2(int u,int tp)
{
    top[u]=tp; dfn[u]=++tot; rk[tot]=u; 
    if(son[u]) dfs2(son[u],tp);
    for(int i=hd[u];i;i=t[i].nxt) {
        int v=t[i].to;
        if(v==f[u]||v==son[u]) continue ;
        dfs2(v,v);
    }
}

void getcol(int l,int r,int ql,int qr,int id,int p)
{
    if(ql<=l&&r<=qr) {
        if(ql==l) coll[id]=lc[p];
        if(qr==r) colr[id]=rc[p];
        return ;
    }
    int mid=(l+r)>>1; push_down(p);
    if(qr>mid) getcol(mid+1,r,ql,qr,id,rs);
    if(ql<=mid) getcol(l,mid,ql,qr,id,ls);
    push_up(p);
}

int query(int l,int r,int ql,int qr,int id,int p)
{	
    if(ql<=l&&r<=qr) return v[p]; 
    int mid=(l+r)>>1; int lt=0,rt=0,res=0; push_down(p);
    if(ql<=mid) res+=query(l,mid,ql,qr,id,ls),lt=1;
    if(qr>mid) res+=query(mid+1,r,ql,qr,id,rs),rt=1;
    if(lt&&rt) res-=(rc[ls]==lc[rs]); return res;
}

void update(int l,int r,int ql,int qr,int val,int p)
{
    if(ql<=l&&r<=qr) {
        tag[p]=val;
        v[p]=1; lc[p]=rc[p]=val;
        return ;
    }
    int mid=(l+r)>>1; push_down(p);
    if(ql<=mid) update(l,mid,ql,qr,val,ls);
    if(qr>mid) update(mid+1,r,ql,qr,val,rs);
    push_up(p);
}

void solve(int x,int y)
{
    int ans=0,las1=-1,las2=-1; coll[0]=coll[1]=colr[0]=colr[1]=-1; //注意颜色可能为0,因为这里调了好久
    int fx=top[x],fy=top[y];
    while(fx!=fy) {
        if(dep[fx]>=dep[fy]) {
            ans+=query(1,n,dfn[fx],dfn[x],0,1);
            getcol(1,n,dfn[fx],dfn[x],0,1);
            if(las1==colr[0]) --ans;
            x=f[fx],fx=top[x]; las1=coll[0];
        }
        else { 
            ans+=query(1,n,dfn[fy],dfn[y],1,1);
            getcol(1,n,dfn[fy],dfn[y],1,1);
            if(las2==colr[1]) --ans;
            y=f[fy],fy=top[y]; las2=coll[1];
        } 
    } 
 
    if(dfn[x]>dfn[y]) swap(x,y),swap(las1,las2);
    getcol(1,n,dfn[x],dfn[y],1,1);
    printf("%d\n",ans+query(1,n,dfn[x],dfn[y],1,1)-(colr[1]==las2)-(coll[1]==las1));
}

void modify(int x,int y,int z)
{
    int fx=top[x],fy=top[y];
    while(fx!=fy) {
        if(dep[fx]>=dep[fy]) {
            update(1,n,dfn[fx],dfn[x],z,1);
            x=f[fx],fx=top[x];
        }
        else {
            update(1,n,dfn[fy],dfn[y],z,1);
            y=f[fy],fy=top[y];
        }
    }
    if(dfn[x]>dfn[y]) swap(x,y);
    update(1,n,dfn[x],dfn[y],z,1);
}

int main()
{
    scanf("%d%d",&n,&m); char opt[5]; int u,v,w;
    for(int i=1;i<=n;++i) scanf("%d",a+i);
    for(int i=1;i<n;++i) {
        scanf("%d%d",&u,&v);
        add(u,v); add(v,u);
    }
    dfs1(1,0); dfs2(1,1); build(1,n,1);
    for(int i=1;i<=m;++i) {
        scanf("%s",opt);
        if(opt[0]=='Q') {
            scanf("%d%d",&u,&v);
            solve(u,v);
        }
        else if (opt[0]=='C') {
            scanf("%d%d%d",&u,&v,&w);
            modify(u,v,w);
        }
    }
    return 0;
}
posted @ 2019-02-27 19:22  cloud_9  阅读(162)  评论(0编辑  收藏  举报