BZOJ3531 [Sdoi2014]旅行 树链剖分 线段树

原文链接:http://www.cnblogs.com/zhouzhendong/p/8080189.html


题目传送门 - BZOJ3531


题意概括

  一棵树,n个节点,每一个节点两个值,一个颜色,一个权值。

  4种操作:

  1. 修改某一个节点的颜色

  2. 修改某一个节点的权值

  3. 查询两点之间某一颜色的节点最大权值

  4. 查询两点之间某一颜色的节点权值和


 

题解

  首先闭着眼睛写上树链剖分。

  因为题目里面说了,颜色的值<=100000。

  所以我们马上想到的开100000个线段树。

  那么修改什么的都是log2n的,时间没问题了。

  那么空间显然要炸。

  怎么做——动态开点啊。

  操作涉及的点很少,所以空间复杂度也是(q+n) log n

  然后就水过了、


 

代码

#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cmath>
using namespace std;
const int N=100005,S=N*2*20;
bool isd(char ch){return '0'<=ch&&ch<='9';}
int read(){
	int res=0;
	char ch=getchar();
	while (!isd(ch))
		ch=getchar();
	while (isd(ch))
		res=res*10+ch-48,ch=getchar();
	return res;
}
struct Gragh{
	int cnt,y[N*2],nxt[N*2],fst[N];
	void clear(){
		cnt=0;
		memset(fst,0,sizeof fst);
	}
	void add(int a,int b){
		y[++cnt]=b,nxt[cnt]=fst[a],fst[a]=cnt;
	}
}g;
int n,q,root[N],w[N],c[N];
int fa[N],son[N],size[N],depth[N],top[N],p[N],ap[N],cnp=0;
int ls[S],rs[S],Max[S],sum[S],tot=0;
void Get_Gen_Info(int rt,int pre,int d){
	size[rt]=1,fa[rt]=pre,son[rt]=-1,depth[rt]=d;
	for (int i=g.fst[rt];i;i=g.nxt[i])
		if (g.y[i]!=pre){
			int s=g.y[i];
			Get_Gen_Info(s,rt,d+1);
			size[rt]+=size[s];
			if (son[rt]==-1||size[s]>size[son[rt]])
				son[rt]=s;
		}
}
void Get_Top(int rt,int tp){
	top[rt]=tp;
	ap[p[rt]=++cnp]=rt;
	if (son[rt]==-1)
		return;
	Get_Top(son[rt],tp);
	for (int i=g.fst[rt];i;i=g.nxt[i]){
		int s=g.y[i];
		if (s!=fa[rt]&&s!=son[rt])
			Get_Top(s,s);
	}
}
void pushup(int rt){
	Max[rt]=max(Max[ls[rt]],Max[rs[rt]]);
	sum[rt]=sum[ls[rt]]+sum[rs[rt]];
}
void change(int &rt,int L,int R,int pos,int v){
	if (!rt)
		rt=++tot;
	if (L==R){
		Max[rt]=sum[rt]=v;
		return;
	}
	int mid=(L+R)>>1;
	if (pos<=mid)
		change(ls[rt],L,mid,pos,v);
	else
		change(rs[rt],mid+1,R,pos,v);
	pushup(rt);
}
int query(int rt,int L,int R,int xL,int xR,int op){
	if (!rt||R<xL||L>xR)
		return 0;
	if (xL<=L&&R<=xR)
		return op?Max[rt]:sum[rt];
	int mid=(L+R)>>1;
	int ansL=query(ls[rt],L,mid,xL,xR,op);
	int ansR=query(rs[rt],mid+1,R,xL,xR,op);
	return op?max(ansL,ansR):(ansL+ansR);
}
int Tquery(int a,int b,int op){
	int f1=top[a],f2=top[b],color=c[a],ans=0;
	while (f1!=f2){
		if (depth[f1]<depth[f2])
			swap(f1,f2),swap(a,b);
		int v=query(root[color],1,n,p[f1],p[a],op);
		ans=op?max(ans,v):(ans+v);
		a=fa[f1],f1=top[a];
	}
	if (depth[a]>depth[b])
		swap(a,b);
	int v=query(root[color],1,n,p[a],p[b],op);
	ans=op?max(ans,v):(ans+v);
	return ans;
}
int main(){
	n=read(),q=read();
	for (int i=1;i<=n;i++)
		w[i]=read(),c[i]=read();
	g.clear();
	for (int i=1,a,b;i<n;i++){
		a=read(),b=read();
		g.add(a,b);
		g.add(b,a);
	}
	Get_Gen_Info(1,0,0);
	Get_Top(1,1);
	for (int i=1;i<=n;i++)
		change(root[c[i]],1,n,p[i],w[i]);
	for (int i=1;i<=q;i++){
		char op[5];
		int x,y;
		scanf("%s",op);
		x=read(),y=read();
		if (op[0]=='C'&&op[1]=='C'){
			change(root[c[x]],1,n,p[x],0);
			change(root[c[x]=y],1,n,p[x],w[x]);
		}
		if (op[0]=='C'&&op[1]=='W')
			change(root[c[x]],1,n,p[x],w[x]=y);
		if (op[0]=='Q'&&op[1]=='S')
			printf("%d\n",Tquery(x,y,0));
		if (op[0]=='Q'&&op[1]=='M')
			printf("%d\n",Tquery(x,y,1));
	}
	return 0;
}

  

 

posted @ 2017-12-21 13:57  zzd233  阅读(274)  评论(0编辑  收藏  举报