[SDOI2014]旅行,洛谷P3313,主席树+树链剖分

正题

      我不喜欢旅行对不起

      看到题目,就会知道有三个东西要维护,一个是路径,一个是评级,一个是宗教。

      主要是宗教和评级之间的关系,要取路径上宗教为某个特定值的评级最大值或和。

      想到用树链剖分来进行重新编号,使得一条重链上的编号连续,然后对于每一个评级,我们开一棵主席树(动态开点线段树无优化)。那么可以节省下来很多空间。

      然后树链剖分来进行操作并统计答案即可。

      修改宗教和评级相当于就是换根(到另一个宗教的主席树内)和底层信息(向上维护最大值和总和)。

代码<比较简单这题>

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

int n,m;
int w[200010],c[200010];
struct edge{
	int y,next;
}s[200010];
int first[200010];
int len=0;
int fa[200010],image[200010],fact[200010],dep[200010],tot[200010],son[200010],top[200010];
int mmax[20000010];
int total[20000010];
int ls[20000010],rs[20000010];
int root[200010];
int tx,ty;
int x,y;
int d,v;
int ans,op;

void ins(int x,int y){
	len++;
	s[len].y=y;s[len].next=first[x];first[x]=len;
}

void dfs_1(int x){
	tot[x]=1;
	for(int i=first[x];i!=0;i=s[i].next){
		int y=s[i].y;
		if(y!=fa[x]){
			dep[y]=dep[x]+1;
			fa[y]=x;
			dfs_1(y);
			if(tot[son[x]]<tot[y]) son[x]=y;
			tot[x]+=tot[y];
		}
	}
}

void dfs_2(int x,int tp){
	top[x]=tp;image[x]=++len;fact[len]=x;
	if(son[x]!=0) dfs_2(son[x],tp);
	for(int i=first[x];i!=0;i=s[i].next){
		int y=s[i].y;
		if(y!=fa[x] && y!=son[x])
			dfs_2(y,y);
	}
}

void update(int &now,int l,int r){
	if(now==0) now=++len;
	total[now]+=d;
	if(l==r) {
		if(d>0) mmax[now]=d;
		else mmax[now]=0;
		return ;
	}
	if(v<=(l+r)/2) update(ls[now],l,(l+r)/2);
	else update(rs[now],(l+r)/2+1,r);
	mmax[now]=max(mmax[ls[now]],mmax[rs[now]]);
}

void change_c(){
	scanf("%d %d",&x,&y);
	v=image[x];d=-w[x];
	update(root[c[x]],1,n);
	c[x]=y;d=w[x];
	update(root[c[x]],1,n);
}

void change_w(){
	scanf("%d %d",&x,&y);
	v=image[x];d=-w[x];
	update(root[c[x]],1,n);
	w[x]=y;d=w[x];
	update(root[c[x]],1,n);
}

int query_sum(int now,int l,int r,int x,int y){
	if(x==l && y==r) return total[now];
	if(r<=(x+y)/2) return query_sum(ls[now],l,r,x,(x+y)/2);
	else if((x+y)/2<l) return query_sum(rs[now],l,r,(x+y)/2+1,y);
	else return query_sum(ls[now],l,(x+y)/2,x,(x+y)/2)+query_sum(rs[now],(x+y)/2+1,r,(x+y)/2+1,y);
}

int get_sum(){
	scanf("%d %d",&x,&y);
	op=x;
	tx=top[x],ty=top[y];
	ans=0;
	while(tx!=ty){
		if(dep[tx]>dep[ty]){
			swap(x,y);swap(tx,ty);
		}
		ans+=query_sum(root[c[op]],image[ty],image[y],1,n);
		y=fa[ty];ty=top[y];
	}
	if(dep[x]>dep[y]) swap(x,y);
	ans+=query_sum(root[c[op]],image[x],image[y],1,n);
	return ans;
}

int query_max(int now,int l,int r,int x,int y){
	if(x==l && y==r) return mmax[now];
	if(r<=(x+y)/2) return query_max(ls[now],l,r,x,(x+y)/2);
	else if((x+y)/2<l) return query_max(rs[now],l,r,(x+y)/2+1,y);
	else return max(query_max(ls[now],l,(x+y)/2,x,(x+y)/2),query_max(rs[now],(x+y)/2+1,r,(x+y)/2+1,y));
}

int get_max(){
	scanf("%d %d",&x,&y);
	op=x;
	tx=top[x],ty=top[y];
	ans=0;
	while(tx!=ty){
		if(dep[tx]>dep[ty]){
			swap(x,y);swap(tx,ty);
		}
		ans=max(ans,query_max(root[c[op]],image[ty],image[y],1,n));
		y=fa[ty];ty=top[y];
	}
	if(dep[x]>dep[y]) swap(x,y);
	ans=max(ans,query_max(root[c[op]],image[x],image[y],1,n));
	return ans;
}

int main(){
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d %d",&w[i],&c[i]);
	for(int i=1;i<=n-1;i++){
		scanf("%d %d",&x,&y);
		ins(x,y);
		ins(y,x);
	}
	dep[1]=1;tot[1]=0;son[1]=0;fa[1]=0;dfs_1(1);
	len=0;dfs_2(1,1);
	len=0;
	for(int i=1;i<=n;i++){
		v=image[i];d=w[i];
		update(root[c[i]],1,n);
	}
	char ch[10];
	while(m--){
		scanf("%s",ch);
		if(ch[1]=='C') change_c();
		else if(ch[1]=='W') change_w();
		else if(ch[1]=='S') printf("%d\n",get_sum());
		else if(ch[1]=='M') printf("%d\n",get_max());
	}
}

     

猜你喜欢

转载自blog.csdn.net/deep_kevin/article/details/80487925
今日推荐