BZOJ3531 SDOI2014 旅行 树链剖分+线段树

每个宗教建一颗线段树,然后随便做……

考虑到如果把每一棵线段树都建完全会MLE,所以我们开动态内存。因为给出的评级都是正整数,所以如果一个区间的和为0,delete掉

#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[MAXN*2];
struct NODE{
	int v,f,c,son,col,mark,depth,belong;
	HASH *child;
}node[MAXN];
typedef struct TREE{
	int l,r,s,maximum;
	TREE *lchild,*rchild;
	TREE(){}
	TREE(int _l,int _r):l(_l),r(_r),lchild(0),rchild(0){}
} *ROOT;
ROOT root[MAXN];
int N,Q,cnt;
char s[6+2];

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

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

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

void Pushup(ROOT &x){
	x->s=x->maximum=0;
	if(x->lchild) x->s+=x->lchild->s,x->maximum=max(x->maximum,x->lchild->maximum);
	if(x->rchild) x->s+=x->rchild->s,x->maximum=max(x->maximum,x->rchild->maximum);
}

void Update(ROOT &x,int l,int r,int p,int v){
	if(!x) x=new TREE(l,r);
	if(l==r){
		if(!v) delete x,x=0;
		else x->s=x->maximum=v;
		return;
	}

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

	Pushup(x);
    if(!x->s) delete x,x=0;
}

int Find_Sum(ROOT &x,int l,int r){
    if(!x) return 0;
	if(x->l>=l && x->r<=r) return x->s;

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

	return ret;
}

int Query_Sum(int u,int v){
	int ret=0,col=node[u].col;
	while(node[u].belong!=node[v].belong){
		if(node[node[u].belong].depth<node[node[v].belong].depth) swap(u,v);
		ret+=Find_Sum(root[col],node[node[u].belong].mark,node[u].mark);
		u=node[node[u].belong].f;
	}

	if(node[u].depth<node[v].depth) swap(u,v);
	ret+=Find_Sum(root[col],node[v].mark,node[u].mark);

	return ret;
}

int Find_Max(ROOT &x,int l,int r){
    if(!x) return -1;
	if(x->l>=l && x->r<=r) return x->maximum;

	int m=(x->l+x->r)>>1,ret=-1;
	if(l<=m) ret=max(ret,Find_Max(x->lchild,l,r));
	if(r>m) ret=max(ret,Find_Max(x->rchild,l,r));

	return ret;
}

int Query_Max(int u,int v){
	int ret=-1,col=node[u].col;
	while(node[u].belong!=node[v].belong){
		if(node[node[u].belong].depth<node[node[v].belong].depth) swap(u,v);
		ret=max(ret,Find_Max(root[col],node[node[u].belong].mark,node[u].mark));
		u=node[node[u].belong].f;
	}

	if(node[u].depth<node[v].depth) swap(u,v);
	ret=max(ret,Find_Max(root[col],node[v].mark,node[u].mark));

	return ret;
}

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

	scanf("%d %d",&N,&Q);
	for(int i=1;i<=N;i++) scanf("%d %d",&node[i].v,&node[i].col);
	for(int i=1,u,v;i<N;i++){
		scanf("%d %d",&u,&v);
		Insert(u,v),Insert(v,u);
	}

	cnt=0,DFS1(1,0,0),DFS2(1,1);

	for(int i=1;i<=N;i++) Update(root[node[i].col],1,N,node[i].mark,node[i].v);

	for(int i=1,x,y,v;i<=Q;i++){
		scanf("%s %d %d",s,&x,&y);
		if(strstr(s,"CC")){
			v=Find_Sum(root[node[x].col],node[x].mark,node[x].mark);
			Update(root[node[x].col],1,N,node[x].mark,0);
			node[x].col=y;
			Update(root[node[x].col],1,N,node[x].mark,v);
		}
		if(strstr(s,"CW")) Update(root[node[x].col],1,N,node[x].mark,y);
		if(strstr(s,"QS")) printf("%d\n",Query_Sum(x,y));
		if(strstr(s,"QM")) printf("%d\n",Query_Max(x,y));
	}

	return 0;
}


你可能感兴趣的:(BZOJ3531 SDOI2014 旅行 树链剖分+线段树)