BZOJ3531 SDOI2014旅行 【离线+树链剖分】

传送门


SOL:

首先不难发现此题是一个树上修改。树剖是一定的。
但是,询问的是一条路上同一颜色的权值和,颜色最多有1e5种,如果每一种颜色都维护一棵线段树显然要爆空间。
此时我们可以想到离线。
先处理一种颜色的修改和询问,统计好答案清空后再处理下一种颜色。
(思路类似 SDOI2008郁闷的小J)
注意一点,这里是单点修改。如果是区间修改最坏会被卡成 n 2 n^2 n2。。。


代码细节:
一,结构体定义

c: 颜色
t:此操作的时间
f::操作类型(0:询问路径最大值 1:询问路径和 2:单点修改)
x,y:起点和终点(单点修改时标号为x)
k:单点修改的值

排序顺序:第一关键字:颜色,第二关键字:时间

struct atom{
	int c,t,f,x,y,k;
	bool operator <(const atom & k ) const{
		return (c==k.c) ? t<k.t : c<k.c;
	}
}t[1000005];

二, 改颜色处理
1.对于原来的颜色,会对之后的询问产生影响
2.对于改变后的颜色,会对之后的询问产生影响

		if(s[0]=='C'){
			if(s[1]=='C'){
				++tim;t[tim]=(atom){col[x],tim,2,x,0,0};
				col[x]=y;
				++tim;t[tim]=(atom){col[x],tim,2,x,0,num[x]};	
			}

三,清空小技巧

可以在同种颜色的最后清空,总复杂度 O(n*logn)

	for(int i=1;i<=n;++i){
		++tim;t[tim]=(atom){col[i],1e9,2,i,0,0};
	}

代码:

#include
using namespace std;
#define sf scanf
#define pf printf
#define lc (p<<1)
#define rc ((p<<1)|1)
#define ll long long
const int maxn=1e5+10;
int seg[maxn],top[maxn],son[maxn],dep[maxn],fa[maxn],col[maxn],mx[maxn<<2],n,m,tim=0,num[maxn],siz[maxn];
ll sum[maxn<<2];
vector <int> G[maxn];
struct atom{
	int c,t,f,x,y,k;
	bool operator <(const atom & k ) const{
		return (c==k.c) ? t<k.t : c<k.c;
	}
}t[1000005];
//f:0  getmax f: 1 getsum f:2 change
struct node{
	ll t,s;
	bool operator <(const node & k ) const{
		return t<k.t;
	}
};
vector <node> P;
inline void change(int p,int l,int r,int k,int v){
	if(l==r){
		sum[p]=mx[p]=v;
		return;
	}
	int mid=(l+r)>>1;
	if(k>mid) change(rc,mid+1,r,k,v);
	else change(lc,l,mid,k,v);
	sum[p]=sum[lc]+sum[rc];mx[p]=max(mx[lc],mx[rc]);
}
inline ll query(int p,int l,int r,int ql,int qr,bool f){
	if(ql>qr)return 0;
	if(ql<=l&&r<=qr){
		return f ? sum[p] : mx[p];
	}
	int mid=(l+r)>>1;
	if(ql>mid) return query(rc,mid+1,r,ql,qr,f);
	else if(qr<=mid) return query(lc,l,mid,ql,qr,f);
	else return  f ? query(lc,l,mid,ql,qr,f)+query(rc,mid+1,r,ql,qr,f) : max(query(lc,l,mid,ql,qr,f),query(rc,mid+1,r,ql,qr,f));
}
void dfs(int u){
	siz[u]=1;
	for(int i=0;i<G[u].size();++i){
		int v=G[u][i];if(v==fa[u])continue;
		fa[v]=u;dep[v]=dep[u]+1;
		dfs(v);
		siz[u]+=siz[v];
		if(siz[v]>siz[son[u]])son[u]=v;
	}
}
void dfs2(int u){
	int v=son[u];
	if(v){
		top[v]=top[u];seg[v]=++seg[0];
		dfs2(v);
	}
	for(int i=0;i<G[u].size();++i){
		v=G[u][i];if(top[v])continue;
		top[v]=v;seg[v]=++seg[0];
		dfs2(v);
	}
}
inline ll answer(int x,int y,int f){
	int fx=top[x],fy=top[y];
	ll ret=0;
	while(fx!=fy){
		if(dep[fx]<dep[fy])swap(x,y),swap(fx,fy);
		ret= f? ret+query(1,1,seg[0],seg[fx],seg[x],f) : max(ret,query(1,1,seg[0],seg[fx],seg[x],f));
		x=fa[fx];fx=top[x];
	}
	if(dep[x]>dep[y])swap(x,y);
	return f? ret+query(1,1,seg[0],seg[x],seg[y],f) : max(ret,query(1,1,seg[0],seg[x],seg[y],f));
}
char s[20];
signed main(){
	sf("%d%d",&n,&m);
	for(int i=1;i<=n;++i){
		sf("%d%d",&num[i],&col[i]);
		++tim;t[tim]=(atom){col[i],tim,2,i,0,num[i]};
	}
	for(int i=1;i<n;++i){
		int x,y;sf("%d%d",&x,&y);
		G[x].push_back(y);G[y].push_back(x);
	}
	top[1]=dep[1]=seg[1]=seg[0]=1;
	dfs(1);dfs2(1);
	for(int i=1;i<=m;++i){
		sf("\n%s",s);int x,y;sf("%d%d",&x,&y);
		if(s[0]=='C'){
			if(s[1]=='C'){
				++tim;t[tim]=(atom){col[x],tim,2,x,0,0};
				col[x]=y;
				++tim;t[tim]=(atom){col[x],tim,2,x,0,num[x]};	
			}
			if(s[1]=='W'){
				num[x]=y;
				++tim;t[tim]=(atom){col[x],tim,2,x,0,num[x]};
			}
		}
		if(s[0]=='Q'){
			if(s[1]=	='S'){
				++tim;t[tim]=(atom){col[y],tim,1,x,y,0};
			}
			if(s[1]=='M'){
				++tim;t[tim]=(atom){col[y],tim,0,x,y,0};
			}
		}
	}
	for(int i=1;i<=n;++i){
		++tim;t[tim]=(atom){col[i],1e9,2,i,0,0};
	}
	sort(t+1,t+tim+1);
	for(int i=1;i<=tim;++i){
		if(t[i].f==2){
			change(1,1,seg[0],seg[t[i].x],t[i].k);
		}
		else P.push_back((node){t[i].t,answer(t[i].x,t[i].y,t[i].f)});
	}
	sort(P.begin(),P.end());
	for(int i=0;i<P.size();++i){
		cout<<P[i].s<<"\n";
	}
	return 0;
}

你可能感兴趣的:(数据结构,树链剖分,woj)