树链剖分相关

[ZJOI2008]树的统计

#include <bits/stdc++.h>
using namespace std;
#define maxn 30010

int AKIOI_maxd,AKIOI_sum,n,m,tot=0,head[maxn],top[maxn],rev[maxn],seg[maxn],f[maxn],w[maxn],dep[maxn],size[maxn],son[maxn];
struct edge {
	int v,nxt;
}e[maxn<<1];
char s[10];

inline int read_() {
	int x_=0,f_=1;char c_=getchar();
	while(c_<'0'||c_>'9') {if(c_=='-') f_=-1;c_=getchar();}
	while(c_>='0'&&c_<='9') {x_=(x_<<1)+(x_<<3)+c_-'0';c_=getchar();}
	return x_*f_;
}

inline void add_(int u,int v) {
	e[++tot].v=v;
	e[tot].nxt=head[u];
	head[u]=tot;
}

void dfs_1_(int u,int fa) {
	dep[u]=dep[fa]+1;
	f[u]=fa;
	size[u]=1;
	for(int i=head[u];~i;i=e[i].nxt) {
		int v=e[i].v;
		if(v==fa) continue;
		dfs_1_(v,u);
		size[u]+=size[v];
		if(size[v]>size[son[u]]) son[u]=v;
	}
}

void dfs_2_(int u,int fa) {
	if(son[u]) {
		seg[son[u]]=++seg[0];
		top[son[u]]=top[u];
		rev[seg[0]]=son[u];
		dfs_2_(son[u],u);
	}
	for(int i=head[u];~i;i=e[i].nxt) {
		int v=e[i].v;
		if(!top[v]) {
			seg[v]=++seg[0];
			top[v]=v;
			rev[seg[0]]=v;
			dfs_2_(v,u);
		}
	}
}

struct seg_tree {
	struct node {
		int maxd,sum;
	}tr[maxn<<2];

#define lson l,mid,nod<<1
#define rson mid+1,r,nod<<1|1
	
	inline void pushup_(int nod) {
		tr[nod].maxd=max(tr[nod<<1].maxd,tr[nod<<1|1].maxd);
		tr[nod].sum=tr[nod<<1].sum+tr[nod<<1|1].sum;
	}
	void build_(int l,int r,int nod) {
		if(l==r) {
			tr[nod].maxd=tr[nod].sum=w[rev[l]];
			return;
		}
		int mid=(l+r)>>1;
		build_(lson);build_(rson);
		pushup_(nod);
	}
	void update_(int l,int r,int nod,int k,int v) {
		if(l==r&&l==k) {
			tr[nod].maxd=tr[nod].sum=v;
			return;
		} 
		int mid=(l+r)>>1;
		if(k<=mid) update_(lson,k,v);
		else update_(rson,k,v);
		pushup_(nod);
	}
	void query_(int l,int r,int nod,int LL,int RR) {
		if(LL<=l&&RR>=r) {
			AKIOI_maxd=max(AKIOI_maxd,tr[nod].maxd);
			AKIOI_sum+=tr[nod].sum;
			return;
		}
		int mid=(l+r)>>1;
		if(LL<=mid) query_(lson,LL,RR);
		if(RR>mid) query_(rson,LL,RR);
	}
}tree_;

inline void solve_(int x,int y) {
	AKIOI_maxd=-2139062143,AKIOI_sum=0;
	int fx=top[x],fy=top[y];
	while(fx!=fy) {
		if(dep[fx]<dep[fy]) swap(x,y),swap(fx,fy);
		tree_.query_(1,seg[0],1,seg[fx],seg[x]);
		x=f[fx];fx=top[x];
	}
	if(dep[x]>dep[y]) swap(x,y);
	tree_.query_(1,seg[0],1,seg[x],seg[y]);
}

void readda_(){
	n=read_();
	int x,y;memset(head,-1,sizeof(head));
	for(int i=1;i<n;++i) {
		x=read_();y=read_();
		add_(x,y);add_(y,x);
	}
	for(int i=1;i<=n;++i) w[i]=read_();
	dfs_1_(1,0);
	seg[0]=seg[1]=top[1]=rev[1]=1;
	dfs_2_(1,0);
	tree_.build_(1,seg[0],1);
	m=read_();
	while(m--) {
		scanf("%s",s);
		x=read_();y=read_();
		if(s[0]=='C') {
			tree_.update_(1,seg[0],1,seg[x],y);
		}
		else if(s[1]=='M') {
			solve_(x,y);
			printf("%d\n",AKIOI_maxd);
		}
		else if(s[1]=='S') {
			solve_(x,y);
			printf("%d\n",AKIOI_sum);
		}
	}
}

int main() {
//	freopen("a.txt","r",stdin);
	readda_();
	return 0;
}

换根树链剖分

#include <bits/stdc++.h>
using namespace std;
#define maxn 100010

int root,m,n,w[maxn],head[maxn],dep[maxn],top[maxn],seg[maxn],rev[maxn],f[maxn],size[maxn],son[maxn],tot=0;
struct edge {
	int v,nxt;
}e[maxn<<1];

inline int read_() {
	int x_=0,f_=1;char c_=getchar();
	while(c_<'0'||c_>'9') {if(c_=='-') f_=-1;c_=getchar();}
	while(c_>='0'&&c_<='9') {x_=(x_<<1)+(x_<<3)+c_-'0';c_=getchar();}
	return x_*f_;
}

inline void add_(int u,int v) {
	e[++tot].v=v;
	e[tot].nxt=head[u];
	head[u]=tot;
}

void dfs_1_(int u,int fa) {
	dep[u]=dep[fa]+1;
	f[u]=fa;size[u]=1;
	for(int i=head[u];~i;i=e[i].nxt) {
		int v=e[i].v;
		if(v==fa) continue;
		dfs_1_(v,u);
		size[u]+=size[v];
		if(size[v]>size[son[u]]) son[u]=v;
	}
}

void dfs_2_(int u,int fa) {
	if(son[u]) {
		seg[son[u]]=++seg[0];
		top[son[u]]=top[u];
		rev[seg[0]]=son[u];
		dfs_2_(son[u],u);
	}
	for(int i=head[u];~i;i=e[i].nxt) {
		int v=e[i].v;
		if(v==fa) continue;
		if(!top[v]) {
			seg[v]=++seg[0];
			top[v]=v;
			rev[seg[0]]=v;
			dfs_2_(v,u);
		}
	}
}

struct seg_tree {
	struct node {
		long long sum,la;
	}tr[maxn<<2];
	#define lson l,mid,nod<<1
	#define rson mid+1,r,nod<<1|1
	inline void pushup_(int nod) {
		tr[nod].sum=tr[nod<<1].sum+tr[nod<<1|1].sum;
	}
	void build_(int l,int r,int nod) {
		if(l==r) {
			tr[nod].sum=w[rev[l]];
			return ;
		}
		int mid=(l+r)>>1;
		build_(lson);build_(rson);
		pushup_(nod);
	}
	inline void xiugai_(int l,int r,int nod,long long v) {
		tr[nod].sum += ( r-l+1 ) * v; tr[nod].la += v;
	}
	void update_(int l,int r,int nod,int LL,int RR,long long v) {
		if(LL<=l&&RR>=r) {
			xiugai_(l,r,nod,v);
			return ;
		}
		int mid=(l+r)>>1;
		if(tr[nod].la!=0) {
			xiugai_(lson,tr[nod].la);xiugai_(rson,tr[nod].la);tr[nod].la=0;
		}
		if(LL<=mid) update_(lson,LL,RR,v);
		if(RR>mid) update_(rson,LL,RR,v);
		pushup_(nod);
	}
	long long query_(int l,int r,int nod,int LL,int RR) {
		if(LL<=l&&RR>=r) return tr[nod].sum;
		int mid=(l+r)>>1;
		if(tr[nod].la!=0) {
			xiugai_(lson,tr[nod].la);xiugai_(rson,tr[nod].la);tr[nod].la=0;
		}
		long long ans=0;
		if(LL<=mid) ans+=query_(lson,LL,RR);
		if(RR>mid) ans+=query_(rson,LL,RR);
		return ans;
	}
}tree_;

inline int LCA_(int x,int y) {
	while(top[x]!=top[y]) {
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		x=f[top[x]];
	}
	if(dep[x]>dep[y]) swap(x,y);
	return x;
}

inline int find_(int x,int y) {
	while(top[x]!=top[y]) {
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		if(f[top[x]]==y) return top[x];
		x=f[top[x]];
	}
	if(dep[x]>dep[y]) swap(x,y);
	return son[x];
}

inline void solve_2_(int x,int y,long long z) {
	while(top[x]!=top[y]) {
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		tree_.update_(1,seg[0],1,seg[top[x]],seg[x],z);
		x=f[top[x]];
	}
	if(dep[x]>dep[y]) swap(x,y);
	tree_.update_(1,n,1,seg[x],seg[y],z);
}

inline void solve_3_(int x,long long z) {
	if(x==root) return tree_.update_(1,n,1,1,n,z);
	int lca=LCA_(x,root);
	if(lca!=x) return tree_.update_(1,n,1,seg[x],seg[x]+size[x]-1,z);
	else {
		int ch=find_(x,root);
		tree_.update_(1,n,1,1,n,z);
		tree_.update_(1,n,1,seg[ch],seg[ch]+size[ch]-1,-z);
		return ;
	}
} 

inline void solve_4_(int x,int y) {
	long long AKIOI=0;
	while(top[x]!=top[y]) {
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		AKIOI+=tree_.query_(1,n,1,seg[top[x]],seg[x]);
		x=f[top[x]];
	}
	if(dep[x]>dep[y]) swap(x,y);
	AKIOI+=tree_.query_(1,n,1,seg[x],seg[y]);
	printf("%lld\n",AKIOI);
}

inline void solve_5_(int x) {
	long long AKIOI=0;
	if(x==root) {
		AKIOI=tree_.query_(1,n,1,1,n);
		printf("%lld\n",AKIOI);
		return ;
	}
	int lca=LCA_(x,root);
	if(lca!=x) AKIOI=tree_.query_(1,n,1,seg[x],seg[x]+size[x]-1);
	else {
		int ch=find_(x,root);
		AKIOI=tree_.query_(1,n,1,1,n);
		AKIOI-=tree_.query_(1,n,1,seg[ch],seg[ch]+size[ch]-1);
	}
    printf("%lld\n",AKIOI);
	return ;
}

void readda_() {
	n=read_();
	for(int i=1;i<=n;++i) w[i]=read_();
	int x;memset(head,-1,sizeof(head));
	for(int i=2;i<=n;++i) {
		x=read_();add_(i,x);add_(x,i);
	}
	dfs_1_(1,0);
	seg[0]=seg[1]=rev[1]=top[1]=1;
	dfs_2_(1,0);
	tree_.build_(1,seg[0],1);
	m=read_();root=1;
	int pd,y,z;
	while(m--) {
		pd=read_(); 
		if(pd==1) {
			x=read_();
			root=x;
		}
		else if(pd==2) {
			x=read_();y=read_();z=read_();
			solve_2_(x,y,(long long)z);
		}
		else if(pd==3) {
			x=read_();z=read_();
			solve_3_(x,(long long) z);
		}
		else if(pd==4) {
			x=read_();y=read_();
			solve_4_(x,y);
		}
		else if(pd==5) {
			x=read_();
			solve_5_(x);
		}
	}
}

int main() {
	readda_();
	return 0;
}

【模板】树链剖分

  • 注意 d f s 2 dfs_2 dfs2时不要把 t o p [ u ] top[u] top[u]打成 u u u
#include <bits/stdc++.h>
using namespace std;
#define maxn 100010

int n,m,root,w[maxn],mod,tot=0,head[maxn],f[maxn],seg[maxn],top[maxn],rev[maxn],size[maxn],son[maxn],dep[maxn];
long long ans=0;
struct edge {
   int v,nxt;
}e[maxn<<1];

inline int read_() {
   int x_=0,f_=1;char c_=getchar();
   while(c_<'0'||c_>'9') {if(c_=='-') f_=-1;c_=getchar();}
   while(c_>='0'&&c_<='9') {x_=(x_<<1)+(x_<<3)+c_-'0';c_=getchar();}
   return x_*f_;
}

inline void add_(int u,int v) {
   e[++tot].v=v;
   e[tot].nxt=head[u];
   head[u]=tot;
}

void dfs_1_(int u,int fa) {
   dep[u]=dep[fa]+1;
   f[u]=fa;size[u]=1;
   for(int i=head[u];~i;i=e[i].nxt) {
   	int v=e[i].v;
   	if(v==fa) continue;
   	dfs_1_(v,u);
   	size[u]+=size[v];
   	if(size[v]>size[son[u]]) son[u]=v;
   }
}

void dfs_2_(int u,int fa) {
   if(son[u]) {
   	seg[son[u]]=++seg[0];
   	top[son[u]]=top[u];
   	rev[seg[0]]=son[u];
   	dfs_2_(son[u],u);
   }
   for(int i=head[u];~i;i=e[i].nxt) {
   	int v=e[i].v;
   	if(v==fa) continue;
   	if(!top[v]) {
   		seg[v]=++seg[0];
   		top[v]=v;
   		rev[seg[0]]=v;
   		dfs_2_(v,u);
   	}
   }
}

struct seg_tree {
   long long sum[maxn<<2],la[maxn<<2];
   #define lson l,mid,nod<<1
   #define rson mid+1,r,nod<<1|1
   inline void pushup_(int nod) {
   	sum[nod]=sum[nod<<1]+sum[nod<<1|1];
   	sum[nod]%=mod;
   }
   void build_(int l,int r,int nod) {
   	if(l==r) {
   		sum[nod]=w[rev[l]];
   		sum[nod]%=mod;
   		return;
   	}
   	int mid=(l+r)>>1;
   	build_(lson);build_(rson);
   	pushup_(nod);
   }
   inline void xiugai_(int l,int r,int nod,int v) {
   	sum[nod]+=(long long) (r-l+1) * v;sum[nod]%=mod;
   	la[nod]+=v;
   }
   void update_(int l,int r,int nod,int LL,int RR,int v) {
   	if(LL<=l&&RR>=r) {
   		xiugai_(l,r,nod,v);
   		return;
   	}
   	int mid=(l+r)>>1;
		if(la[nod]!=0) {
			xiugai_(lson,la[nod]);xiugai_(rson,la[nod]);la[nod]=0;
   	}
		if(LL<=mid) update_(lson,LL,RR,v);
		if(RR>mid) update_(rson,LL,RR,v);
		pushup_(nod);
   }
   void query_(int l,int r,int nod,int LL,int RR) {
   	if(LL<=l&&RR>=r) {
   		ans+=sum[nod];ans%=mod;
   		return ;
   	}
   	int mid=(l+r)>>1;
   	if(la[nod]!=0) {
   		xiugai_(lson,la[nod]);xiugai_(rson,la[nod]);la[nod]=0;
   	}
   	if(LL<=mid) query_(lson,LL,RR);
   	if(RR>mid) query_(rson,LL,RR);
   }
}tree_;

inline void solve_update_(int x,int y,int z) {
   z%=mod;
   int fx=top[x],fy=top[y];
   while(fx!=fy) {
   	if(dep[fx]<dep[fy]) {
   		swap(fx,fy); swap(x,y);
   	}
   	tree_.update_(1,n,1,seg[fx],seg[x],z);
   	x=f[fx];fx=top[x];
   }
   if(dep[x]>dep[y]) swap(x,y);
   tree_.update_(1,n,1,seg[x],seg[y],z);
}

inline void solve_query_(int x,int y) {
   int fx=top[x],fy=top[y];
   while(fx!=fy) {
   	if(dep[fx]<dep[fy]) {
   		swap(fx,fy);swap(x,y);
   	}
   	tree_.query_(1,n,1,seg[fx],seg[x]);
   	x=f[fx];fx=top[x];ans%=mod;
   }
   if(dep[x]>dep[y]) swap(x,y);
   tree_.query_(1,n,1,seg[x],seg[y]);  ans%=mod;
}

void readda_(){
   n=read_();m=read_();root=read_();mod=read_();
   for(int i=1;i<=n;++i) w[i]=read_();
   int x,y;memset(head,-1,sizeof(head));
   for(int i=1;i<n;++i) {
   	x=read_();y=read_();
   	add_(x,y);add_(y,x);
   }
   dfs_1_(root,0);
   seg[0]=1;top[root]=root;seg[root]=1;rev[1]=root;
   dfs_2_(root,0);
   tree_.build_(1,n,1);
   int pd,z;
   while(m--) {
   	pd=read_();x=read_();
   	if(pd==1) {
   		y=read_();z=read_();
   		solve_update_(x,y,z);
   	}
   	else if(pd==2) {
   		y=read_();ans=0;
   		solve_query_(x,y);
   		printf("%lld\n",ans%mod);
   	}
   	else if(pd==3) {
   		z=read_();
   		tree_.update_(1,n,1,seg[x],seg[x]+size[x]-1,z);
   	}
   	else if(pd==4) {
   		ans=0;
   		tree_.query_(1,n,1,seg[x],seg[x]+size[x]-1);
   		printf("%lld\n",ans%mod);
   	}
   }
}

int main() {
//	freopen("a.txt","r",stdin);
   readda_();
   return 0;
}

[HAOI2015]树上操作

  • 注意线段树修改函数的 v v v要开成 l o n g long long l o n g long long
#include <bits/stdc++.h>
using namespace std;
#define maxn 100010

int f[maxn],size[maxn],son[maxn],seg[maxn],top[maxn],rev[maxn],dep[maxn],n,m,tot=0,head[maxn],w[maxn];
long long ans;
struct edge {
	int v,nxt;
}e[maxn<<1];

inline int read_() {
	int x_=0,f_=1;char c_=getchar();
	while(c_<'0'||c_>'9') {if(c_=='-') f_=-1;c_=getchar();}
	while(c_>='0'&&c_<='9') {x_=(x_<<1)+(x_<<3)+c_-'0';c_=getchar();}
	return x_*f_;
}

inline void add_(int u,int v) {
	e[++tot].v=v;
	e[tot].nxt=head[u];
	head[u]=tot;
}

void dfs_1_(int u,int fa) {
	dep[u]=dep[fa]+1;
	f[u]=fa;size[u]=1;
	for(int i=head[u];~i;i=e[i].nxt) {
		int v=e[i].v;
		if(v==fa) continue;
		dfs_1_(v,u);
		size[u]+=size[v];
		if(size[v]>size[son[u]]) son[u]=v;
	}
}

void dfs_2_(int u,int fa) {
	if(son[u]) {
		seg[son[u]]=++seg[0];
		top[son[u]]=top[u];
		rev[seg[0]]=son[u];
		dfs_2_(son[u],u);
	}
	for(int i=head[u];~i;i=e[i].nxt) {
		int v=e[i].v;
		if(v==fa) continue;
		if(!top[v]) {
			seg[v]=++seg[0];
			top[v]=v;
			rev[seg[0]]=v;
			dfs_2_(v,u);
		}
	}
}

struct seg_tree {
	struct node {
		long long sum,la;
	}tr[maxn<<2];
	#define lson l,mid,nod<<1
	#define rson mid+1,r,nod<<1|1
	inline void pushup_(int nod) {
		tr[nod].sum=tr[nod<<1].sum+tr[nod<<1|1].sum;
	}
	void build_(int l,int r,int nod) {
		if(l==r) {
			tr[nod].sum=w[rev[l]];
			return;
		}
		int mid=(l+r)>>1;
		build_(lson);build_(rson);
		pushup_(nod);
	}
	inline void xiugai_(int l,int r,int nod,long long v) {
		tr[nod].sum+=(r-l+1) * v;tr[nod].la+=v;
	}
	void update_(int l,int r,int nod,int LL,int RR,long long v) {
		if(LL<=l&&RR>=r) {
			xiugai_(l,r,nod,v);
			return ;
		}
		int mid=(l+r)>>1;
		if(tr[nod].la!=0) {
			xiugai_(lson,tr[nod].la);xiugai_(rson,tr[nod].la);tr[nod].la=0;
		}
		if(LL<=mid) update_(lson,LL,RR,v);
		if(RR>mid) update_(rson,LL,RR,v);
		pushup_(nod); 
	}
	void query_(int l,int r,int nod,int LL,int RR) {
		if(LL<=l&&RR>=r) {
			ans+=tr[nod].sum;
			return;
		}
		int mid=(l+r)>>1;
		if(tr[nod].la!=0) {
			xiugai_(lson,tr[nod].la);xiugai_(rson,tr[nod].la);tr[nod].la=0;
		}
		if(LL<=mid) query_(lson,LL,RR);
		if(RR>mid) query_(rson,LL,RR);
	}
}tree_;

inline void solve_query_(int x,int y) {
	int fx=top[x],fy=top[y];
	while(fx!=fy) {
		if(dep[fx]<dep[fy]) {
			swap(fx,fy);swap(x,y);
		}
		tree_.query_(1,seg[0],1,seg[fx],seg[x]);
		x=f[fx];fx=top[x];
	}
	if(dep[x]>dep[y]) swap(x,y);
	tree_.query_(1,seg[0],1,seg[x],seg[y]);
}
void readda_() {
	n=read_();m=read_();
	for(int i=1;i<=n;++i) w[i]=read_();
	int x,y;memset(head,-1,sizeof(head));
	for(int i=1;i<n;++i) {
		x=read_();y=read_();
		add_(x,y);add_(y,x);
	}
	dfs_1_(1,0);
	seg[0]=seg[1]=rev[1]=top[1]=1;
	dfs_2_(1,0);
	tree_.build_(1,seg[0],1);
	int pd;
	while(m--) {
		pd=read_();x=read_();
		if(pd==1) {
			y=read_();
			tree_.update_(1,seg[0],1,seg[x],seg[x],(long long)y);
		}
		else if(pd==2) {
			y=read_();
			tree_.update_(1,seg[0],1,seg[x],seg[x]+size[x]-1,(long long)y);
		}
		else if(pd==3) {
			ans=0;
			solve_query_(1,x);
			printf("%lld\n",ans);
		}
	}
}

int main() {
	freopen("a.txt","r",stdin);
	readda_();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值