BZOJ 3589: 动态树 树链剖分+线段树+树链的并

利用树剖序的一些性质~

这个题可以出到 $sum k=10^5$ 左右.
做法很简单:每次暴力跳重链,并在线段树上查询链和.
查询之后打一个标记,把加过的链都置为 $0$.
这样的话在同一次询问时即使有重复的也无所谓.
然后本次查询后在线段树的 $1$ 号节点再打一个标记,用来将那些置零的标记清空.
这个主要是利用树剖序的连续性质.
具体细节还是需要注意一下.

Code: 

#include <cstdio> 
#include <algorithm>  
#define N 200004
#define ll long long  
#define setIO(s) freopen(s".in","r",stdin) , freopen(s".out","w",stdout)      
using namespace std;   
const ll mod=2147483648; 
void Add(ll &g,ll b) 
{
	g=(g+b)%mod;     
}    
namespace seg 
{
	struct Node 
	{
		int tag,mark; 
		ll sum,sumvir,add;      
	}t[N<<2]; 
	void mark_tag(int now) 
	{
		t[now].mark=1,t[now].tag=0,t[now].sum=t[now].sumvir;   
	} 
	void mark_add(int l,int r,int now,ll v) 
	{
		Add(t[now].add,v), Add(t[now].sumvir,(r-l+1)*v%mod);       
		if(t[now].tag) t[now].sum=0;    
		else t[now].sum=t[now].sumvir;    
	}
	void pushdown(int l,int r,int now) 
	{
		int mid=(l+r)>>1;   
		if(t[now].mark) 
		{
			if(mid>=l) mark_tag(now<<1); 
			if(r>mid)  mark_tag(now<<1|1); 
			t[now].mark=0; 
	 	} 
	 	if(t[now].add) 
	 	{
	 		if(mid>=l) mark_add(l,mid,now<<1,t[now].add); 
	 		if(r>mid)  mark_add(mid+1,r,now<<1|1,t[now].add); 
	 		t[now].add=0; 
	 	}
	}  
	void pushup(int l,int r,int now) 
	{
		int mid=(l+r)>>1;  
		t[now].sum=t[now].sumvir=0; 
		if(mid>=l) Add(t[now].sum,t[now<<1].sum),Add(t[now].sumvir,t[now<<1].sumvir); 
		if(r>mid)  Add(t[now].sum,t[now<<1|1].sum),Add(t[now].sumvir,t[now<<1|1].sumvir);    
		if(t[now].tag) t[now].sum=0;    
	}
	void update_tag(int l,int r,int now,int L,int R) 
	{
		if(l>=L&&r<=R) 
		{
			t[now].tag=1,t[now].sum=t[now].mark=0;     
			return; 
		}    
		pushdown(l,r,now); 
		int mid=(l+r)>>1; 
		if(L<=mid) update_tag(l,mid,now<<1,L,R); 
		if(R>mid)  update_tag(mid+1,r,now<<1|1,L,R);  
		pushup(l,r,now); 
	}
	void update_add(int l,int r,int now,int L,int R,ll v) 
	{   
		if(l>=L&&r<=R) 
		{
			mark_add(l,r,now,v); 
			return; 
		} 
		pushdown(l,r,now); 
		int mid=(l+r)>>1;    
		if(L<=mid) update_add(l,mid,now<<1,L,R,v); 
		if(R>mid)  update_add(mid+1,r,now<<1|1,L,R,v);   
		pushup(l,r,now);   
	}
	ll query(int l,int r,int now,int L,int R) 
	{
		if((l>=L&&r<=R)||(t[now].tag)) return t[now].sum;         
		int mid=(l+r)>>1; 
		pushdown(l,r,now);        
		ll re=0; 
		if(L<=mid) Add(re,query(l,mid,now<<1,L,R)); 
		if(R>mid)  Add(re,query(mid+1,r,now<<1|1,L,R)); 
		return re;    
	}
};          
int n,Q,edges,tim; 
int hd[N],to[N<<1],nex[N<<1],val[N];        
int size[N],son[N],top[N],dfn[N],fa[N],dep[N],st[N],ed[N]; 
void add(int u,int v) 
{
	nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;
}   
void dfs1(int u,int ff) 
{ 
	fa[u]=ff,dep[u]=dep[ff]+1,size[u]=1;    
	for(int i=hd[u];i;i=nex[i]) 
		if(to[i]!=ff) 
		{
			dfs1(to[i],u),size[u]+=size[to[i]]; 
			if(size[to[i]]>size[son[u]]) son[u]=to[i];   
		}
}  
void dfs2(int u,int tp)
{ 
	top[u]=tp,st[u]=dfn[u]=++tim; 
	if(son[u]) dfs2(son[u],tp); 
	for(int i=hd[u];i;i=nex[i]) 
		if(to[i]!=fa[u]&&to[i]!=son[u]) dfs2(to[i],to[i]); 
	ed[u]=tim; 
}   
ll work(int x,int y) 
{
	ll re=0;  
	while(top[x]!=top[y]) 
	{
		if(dep[top[y]]>dep[top[x]]) swap(x,y);    
		Add(re,seg::query(1,n,1,dfn[top[x]],dfn[x]));   
		seg::update_tag(1,n,1,dfn[top[x]],dfn[x]);    
		x=fa[top[x]]; 
	}   
	if(dep[x]<dep[y]) swap(x,y);     
	Add(re,seg::query(1,n,1,dfn[y],dfn[x]));   
	seg::update_tag(1,n,1,dfn[y],dfn[x]);        
	return re;    
}
int main() 
{ 
	int i,j; 
	// setIO("input");  
	scanf("%d",&n);  
	for(i=1;i<n;++i) 
	{
		int u,v; 
		scanf("%d%d",&u,&v),add(u,v),add(v,u); 
	}    
	dfs1(1,0),dfs2(1,1);    
	scanf("%d",&Q); 
	for(int cas=1;cas<=Q;++cas)
	{   
		int opt; 
		scanf("%d",&opt); 
		if(opt==0)
		{  
			int u; 
			ll v; 
			scanf("%d%lld",&u,&v);  
			seg::update_add(1,n,1,st[u],ed[u],v);     
		} 
		if(opt==1) 
		{ 
			ll ans=0; 
			int k,u,v; 
			scanf("%d",&k); 
			for(i=1;i<=k;++i) scanf("%d%d",&u,&v), Add(ans,work(u,v));     
			seg::mark_tag(1); 
			printf("%lld
",ans);     
		}
	}
	return 0;
}

  

原文地址:https://www.cnblogs.com/guangheli/p/11444614.html