#主席树,树链剖分#洛谷 3313 旅行

题目


分析

首先如果没有宗教的限制,那么这道题就是线段树裸题,但是既然有了宗教的限制,那么得开 1 0 5 10^5 105个线段树,那显然是不行的,想到了主席树,综合它们的空间,时间复杂度 O ( m l o g n 2 ) O(mlogn^2) O(mlogn2)


代码

#include <cstdio>
#include <cctype>
#define rr register
#define w0(x,y) query0(rt[be],1,n,x,y)
#define W0(x,y) query1(rt[be],1,n,x,y) 
using namespace std;
const int N=100011; struct node{int y,next;}e[N<<1];
int dep[N],fat[N],son[N],rt[N],big[N],top[N],dfn[N],W[N],bel[N],hs[N],ls[N*200],rs[N*200],w1[N*200],w2[N*200],n,m,tot,cnt,K=1; 
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline signed max(int a,int b){return a>b?a:b;}
inline void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline void dfs1(int x,int fa){
	dep[x]=dep[fa]+1,fat[x]=fa,son[x]=1;
	for (rr int i=hs[x],mson=-1;i;i=e[i].next)
	if (e[i].y!=fa){
		dfs1(e[i].y,x),son[x]+=son[e[i].y];
		if (son[e[i].y]>mson) big[x]=e[i].y,mson=son[e[i].y];
	}
}
inline void dfs2(int x,int linp){
	dfn[x]=++tot,top[x]=linp;
	if (!big[x]) return; dfs2(big[x],linp);
	for (rr int i=hs[x];i;i=e[i].next)
	if (e[i].y!=fat[x]&&e[i].y!=big[x]) dfs2(e[i].y,e[i].y);
}
inline void Delete(int &k,int l,int r,int x){
	if (l==r) {w1[k]=w2[k]=0; return;}
	rr int mid=(l+r)>>1;
	if (x<=mid) Delete(ls[k],l,mid,x);
	    else Delete(rs[k],mid+1,r,x);
	w1[k]=w1[ls[k]]+w1[rs[k]],w2[k]=max(w2[ls[k]],w2[rs[k]]);
}
inline void update(int &k,int l,int r,int x,int z){
	if (!k) k=++cnt; w1[k]+=z,w2[k]=max(w2[k],z);
	if (l==r) return; rr int mid=(l+r)>>1;
	if (x<=mid) update(ls[k],l,mid,x,z);
	    else update(rs[k],mid+1,r,x,z);
	w1[k]=w1[ls[k]]+w1[rs[k]],w2[k]=max(w2[ls[k]],w2[rs[k]]);
}
inline signed query0(int k,int l,int r,int x,int y){
	if (l==x&&r==y) return w1[k];
	rr int mid=(l+r)>>1;
	if (y<=mid) return query0(ls[k],l,mid,x,y);
	else if (x>mid) return query0(rs[k],mid+1,r,x,y);
	else return query0(ls[k],l,mid,x,mid)+query0(rs[k],mid+1,r,mid+1,y);
}
inline signed query1(int k,int l,int r,int x,int y){
	if (l==x&&r==y) return w2[k];
	rr int mid=(l+r)>>1;
	if (y<=mid) return query1(ls[k],l,mid,x,y);
	else if (x>mid) return query1(rs[k],mid+1,r,x,y);
	else return max(query1(ls[k],l,mid,x,mid),query1(rs[k],mid+1,r,mid+1,y));
}
inline signed Query(int x,int y,int be,bool typ){
	rr int ans=0;
	while (top[x]!=top[y]){
		if (dep[top[x]]<dep[top[y]]) x^=y,y^=x,x^=y;
		ans=!typ?(ans+w0(dfn[top[x]],dfn[x])):max(ans,W0(dfn[top[x]],dfn[x]));
		x=fat[top[x]];
	}
	if (dep[x]>dep[y]) x^=y,y^=x,x^=y;
	return ans=!typ?(ans+w0(dfn[x],dfn[y])):max(ans,W0(dfn[x],dfn[y]));
}
signed main(){
	n=iut(); m=iut();
	for (rr int i=1;i<=n;++i) W[i]=iut(),bel[i]=iut();
	for (rr int i=1;i<n;++i){
		rr int x=iut(),y=iut();
		e[++K]=(node){y,hs[x]},hs[x]=K;
		e[++K]=(node){x,hs[y]},hs[y]=K;
	};
	dfs1(1,0),dfs2(1,1);
	for (rr int i=1;i<=n;++i) update(rt[bel[i]],1,n,dfn[i],W[i]);
	while (m--){
		rr char s[5]; rr int x,y;
		scanf("%s",s); x=iut(),y=iut();
		switch (s[1]){
			case 'C':{
				Delete(rt[bel[x]],1,n,dfn[x]);
				update(rt[bel[x]=y],1,n,dfn[x],W[x]);
				break;
			}
			case 'W':{
				Delete(rt[bel[x]],1,n,dfn[x]);
				update(rt[bel[x]],1,n,dfn[x],W[x]=y);
				break;
			}
			default:{
				print(Query(x,y,bel[x],s[1]=='M')),putchar(10);
				break;
			}
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值