BZOJ 3531[Sdoi2014]旅行

BZOJ 3531[Sdoi2014]旅行


题面描述

传送门

题目分析

可以考虑到,如果这个题所有城市都只信一种宗教的话,就是一个sb树剖,直接进行链的查询和修改就能搞定。多个宗教的话,可以有一种暴力的思路对每一种宗教开线段树。但是空间不大够,考虑动态开点,把每个宗教类型当成不同的树根,然后在这个宗教的树上查询。

是代码呢

#include <bits/stdc++.h>
using namespace std;
#define mid ((l+r)>>1)
const int inf=1e9+7;
const int MAXN=1e5+7;
int size[MAXN],dep[MAXN],f[MAXN],id[MAXN],at[MAXN],top[MAXN],wson[MAXN],a[MAXN],c[MAXN],w[MAXN];
int n,m,cnt;
char s[5];
vector<int> edge[MAXN];
inline int read()
{
    int x=0,c=1;
    char ch=' ';
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    while(ch=='-')c*=-1,ch=getchar();
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*c;
}
struct seg_tree{
	int mx[MAXN<<5],sum[MAXN<<5],T[MAXN],L[MAXN<<5],R[MAXN<<5],size;
	inline int update(int pre,int l,int r,int k,int x){
		int rt=++size;
		L[rt]=L[pre];R[rt]=R[pre];sum[rt]+=sum[pre]+x;mx[rt]=max(mx[pre],x);
		if(l==r) return rt;
		if(k<=mid) L[rt]=update(L[pre],l,mid,k,x);
		else R[rt]=update(R[pre],mid+1,r,k,x);
		return rt;
	}
	inline void del(int u,int l,int r,int k){
		if(l==r){
			sum[u]=mx[u]=0;
			return;
		}
		sum[u]=mx[u]=0;
		if(k<=mid) del(L[u],l,mid,k);
		else del(R[u],mid+1,r,k);
		sum[u]=sum[L[u]]+sum[R[u]];
		mx[u]=max(mx[L[u]],mx[R[u]]);
	}
	inline int query_max(int dl,int dr,int l,int r,int u){
		if(dl<=l&&r<=dr) return mx[u];
		int lmx=-inf,rmx=-inf;
		if(dl<=mid) lmx=query_max(dl,dr,l,mid,L[u]);
		if(dr>mid) rmx=query_max(dl,dr,mid+1,r,R[u]);
		return max(lmx,rmx);
	}
	inline int query_sum(int dl,int dr,int l,int r,int u){
		if(dl<=l&&r<=dr) return sum[u];
		int ans=0;
		if(dl<=mid) ans=query_sum(dl,dr,l,mid,L[u]);
		if(dr>mid) ans+=query_sum(dl,dr,mid+1,r,R[u]);
		return ans;
	}
}seg;
inline void dfs(int u,int fa)
{
	size[u]=1,dep[u]=dep[fa]+1;f[u]=fa;
	for(int i=0;i<edge[u].size();i++){
		int v=edge[u][i];
		if(v==fa) continue;
		dfs(v,u);
		size[u]+=size[v];
		if(size[wson[u]]<size[v]) wson[u]=v;
	}
}
inline void dfs2(int u,int tp)
{
	id[u]=++cnt;w[cnt]=a[u];top[u]=tp;at[cnt]=u;
	if(wson[u]) dfs2(wson[u],tp);
	for(int i=0;i<edge[u].size();i++){
		int v=edge[u][i];
		if(v==f[u]||v==wson[u]) continue;
		dfs2(v,v);
	}
}
inline int query_Max(int x,int y,int u)
{
	int ans=-inf;
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		ans=max(ans,seg.query_max(id[top[x]],id[x],1,n,u));
		x=f[top[x]];
	}
	if(dep[x]>dep[y]) swap(x,y);
	ans=max(ans,seg.query_max(id[x],id[y],1,n,u));
	return ans;
}
inline int query_Sum(int x,int y,int u)
{
	int ans=0;
	while(top[x]!=top[y]){
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		ans+=seg.query_sum(id[top[x]],id[x],1,n,u);
		x=f[top[x]];
	}
	if(dep[x]>dep[y]) swap(x,y);
	ans+=seg.query_sum(id[x],id[y],1,n,u);
	return ans;
}
int main()
{
	n=read();m=read();
	for(int i=1;i<=n;i++){
		a[i]=read();c[i]=read();
	}
	for(int i=1;i<n;i++){
		int x=read(),y=read();
		edge[x].push_back(y);edge[y].push_back(x);
	}
	dfs(1,0);dfs2(1,1);
	for(int i=1;i<=n;i++) seg.T[c[at[i]]]=seg.update(seg.T[c[at[i]]],1,n,i,a[at[i]]);
	
	while(m--){
		scanf("%s",s);
		if(s[1]=='C'){
			int x=read(),k=read();
			seg.del(seg.T[c[x]],1,n,id[x]);
			c[x]=k;
			seg.T[c[x]]=seg.update(seg.T[c[x]],1,n,id[x],a[x]);
		} else if(s[1]=='W') {
			int x=read(),k=read();
			seg.del(seg.T[c[x]],1,n,id[x]);
			a[x]=k;
			seg.T[c[x]]=seg.update(seg.T[c[x]],1,n,id[x],a[x]);
		} else if(s[1]=='M'){
			int x=read(),y=read();
			int ans=query_Max(x,y,seg.T[c[x]]);
			printf("%d\n", ans);
		} else {
			int x=read(),y=read();
			int ans=query_Sum(x,y,seg.T[c[x]]);
			printf("%d\n", ans);
		}
	}
	
}
posted @ 2019-01-07 20:01  ~victorique~  阅读(107)  评论(0编辑  收藏  举报
Live2D