BZOJ2243 SDOI2011 染色 树链剖分+线段树

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

在树上维护答案,当时为了维护两个端点的颜色,只是费尽心机,最后突然发现暴力查找不超时……整个人都不好了

(话说SDOI真的很喜欢树链剖分和数论啊……每年都有一道,不是R1就是R2)

#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;
}


你可能感兴趣的:(BZOJ2243 SDOI2011 染色 树链剖分+线段树)