BZOJ2243 SDOI2011 染色 树链剖分

题意:给定一棵树,维护:1、将a到b路径上所有的点染为c  2、求a到b路径上颜色段的数量。

题解:区间颜色段数=左区间颜色段数+右区间颜色段数-(左区间最右边的颜色==右区间最左边的颜色),用线段树来维护。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;

const int MAXN=100000+2;
struct HASH{
    int u;
    HASH *next;
    HASH(){}
    HASH(int _u,HASH *_next):u(_u),next(_next){}
}mem[2*MAXN];
struct NODE{
    int c,v,d,t,id,mark,f,son;
    HASH *table;
}node[MAXN];
typedef struct ST{
    int l,r,c,lc,rc,same;
    ST *lchild,*rchild;
} *TREE;
TREE root;
int N,M,cnt,mark[MAXN];
char q;

void Insert(int u,int v){ node[u].table=&(mem[cnt++]=HASH(v,node[u].table));}

void DFS1(int x,int f,int d){
    node[x].c=1,node[x].f=f,node[x].d=d;
    for(HASH *p=node[x].table;p;p=p->next)
        if(p->u!=f){
            DFS1(p->u,x,d+1);
            node[x].c+=node[p->u].c;
            if(!node[x].son || node[p->u].c>node[node[x].son].c) node[x].son=p->u;
        }
}

void DFS2(int x,int t){
    node[x].t=t,node[x].mark=++cnt,mark[cnt]=x;
    if(!node[x].son) return;
    DFS2(node[x].son,t);
    for(HASH *p=node[x].table;p;p=p->next)
        if(p->u!=node[x].son && p->u!=node[x].f) DFS2(p->u,p->u);
}

void Pushup(TREE &x){
    x->c=x->lchild->c+x->rchild->c;
    x->lc=x->lchild->lc,x->rc=x->rchild->rc;
    if(x->lchild->rc==x->rchild->lc) x->c--;
}

void Pushdown(TREE &x){
    if(x->same){
        x->lchild->c=x->rchild->c=1;
        x->lchild->lc=x->lchild->rc=x->same;
        x->rchild->lc=x->rchild->rc=x->same;
        x->lchild->same=x->same,x->rchild->same=x->same,x->same=0;
    }
}

void Build(TREE &x,int l,int r){
    x=new ST;
    x->l=l,x->r=r,x->same=0,x->lchild=x->rchild=0;
    if(l==r){
        x->c=1,x->lc=x->rc=node[mark[l]].v;
        return;
    }

    int m=(l+r)>>1;
    Build(x->lchild,l,m),Build(x->rchild,m+1,r);

    Pushup(x);
}

void Update(TREE &x,int l,int r,int c){
    if(l<=x->l && r>=x->r){
        x->c=1,x->lc=x->rc=x->same=c;
        return;
    }

    Pushdown(x);

    int m=(x->l+x->r)>>1;
    if(l<=m) Update(x->lchild,l,r,c);
    if(r>m) Update(x->rchild,l,r,c);

    Pushup(x);
}

void Change(int u,int v,int c){
    while(node[u].t!=node[v].t){
        if(node[node[u].t].d<node[node[v].t].d) swap(u,v);
        Update(root,node[node[u].t].mark,node[u].mark,c);
        u=node[node[u].t].f;
    }

    if(node[u].d>node[v].d) swap(u,v);
    Update(root,node[u].mark,node[v].mark,c);
}

int Query(TREE &x,int l,int r){
    if(l<=x->l && r>=x->r) return x->c;

    Pushdown(x);

    int m=(x->l+x->r)>>1,ret=0;
    if(l<=m) ret+=Query(x->lchild,l,r);
    if(r>m) ret+=Query(x->rchild,l,r);
    if(l<=m && r>m && x->lchild->rc==x->rchild->lc) ret--;

    return ret;
}

int Find(TREE &x,int p){
    if(x->l==x->r) return x->lc;

    Pushdown(x);

    int m=(x->l+x->r)>>1;
    if(p<=m) return Find(x->lchild,p);
    return Find(x->rchild,p);
}

int Summation(int u,int v){
    int ret=0;
    while(node[u].t!=node[v].t){
        if(node[node[u].t].d<node[node[v].t].d) swap(u,v);
        ret+=Query(root,node[node[u].t].mark,node[u].mark);
        u=node[u].t;
        if(Find(root,node[u].mark)==Find(root,node[node[u].f].mark)) ret--;
        u=node[u].f;
    }

    if(node[u].d>node[v].d) swap(u,v);
    ret+=Query(root,node[u].mark,node[v].mark);

    return ret;
}

int main(){
    memset(node,0,sizeof(node));

    cin >> N >> M;
    for(int i=1;i<=N;i++) cin >> node[i].v;
    for(int i=1,u,v;i<N;i++){
        cin >> u >> v;
        Insert(u,v),Insert(v,u);
    }

    DFS1(1,0,1);
    cnt=0,DFS2(1,1);
    cnt=0,Build(root,1,N);

    for(int i=1,a,b,c;i<=M;i++){
        cin >> q;
        cin >> a >> b;
        if(q=='C'){
            cin >> c;
            Change(a,b,c);
        }
        if(q=='Q') cout << Summation(a,b) << endl;
    }

    return 0;
}
View Code

 

posted @ 2017-02-26 13:32  WDZRMPCBIT  阅读(98)  评论(0编辑  收藏  举报