bzoj 2836: 魔法树(树链剖分)

2836: 魔法树

Time Limit: 10 Sec   Memory Limit: 128 MB
Submit: 247   Solved: 96
[ Submit][ Status][ Discuss]

Description

Input

Output

Sample Input

4
0 1
1 2
2 3
4
Add 1 3 1
Query 0
Query 1
Query 2

Sample Output

3
3
2

HINT

Source

[ Submit][ Status][ Discuss]

题解:dfs序+树链剖分

#include
#include
#include
#include
#include
#define N 200003
#define LL long long
using namespace std;
int n,m,t,tot,sz;
LL tr[N*4],delta[N*4];
int point[N],next[N],v[N],belong[N],size[N],son[N],fa[N],deep[N];
int pos[N],l[N],r[N];
void add(int x,int y)
{
	tot++; next[tot]=point[x]; point[x]=tot; v[tot]=y;
	tot++; next[tot]=point[y]; point[y]=tot; v[tot]=x;
}
void dfs(int x,int f)
{
	size[x]=1;
	for (int i=point[x];i;i=next[i])
	 if (v[i]!=f)
	 {
	 	deep[v[i]]=deep[x]+1;
	 	dfs(v[i],x);
	 	fa[v[i]]=x;
	 	size[x]+=size[v[i]];
	 	if (size[v[i]]>size[son[x]])
	 	 son[x]=v[i];
	 }
}
void build(int k,int chain)
{
	belong[k]=chain; pos[k]=++sz;
	l[k]=sz; r[k]=sz;
	if (!son[k]) return;
	build(son[k],chain);
	for (int i=point[k];i;i=next[i])
	 if (v[i]!=fa[k]&&v[i]!=son[k])
	  build(v[i],v[i]);
	r[k]=sz;
}
void pushdown(int now,int l,int r)
{
	if (!delta[now]) return;
	delta[now<<1]+=delta[now];
	delta[now<<1|1]+=delta[now];
	int mid=(l+r)/2;
	tr[now<<1]+=(LL)(mid-l+1)*delta[now];
	tr[now<<1|1]+=(LL)(r-mid)*delta[now];
	delta[now]=0;
}
LL query(int now,int l,int r,int ll,int rr)
{
	if (l>=ll&&r<=rr) return tr[now];
	pushdown(now,l,r);
	int mid=(l+r)/2;
	LL ans=0;
	if (ll<=mid)  ans+=query(now<<1,l,mid,ll,rr);
	if (rr>mid)  ans+=query(now<<1|1,mid+1,r,ll,rr);
	return ans; 
}
void change(int now,int l,int r,int ll,int rr,LL v)
{
	if (l>=ll&&r<=rr){
		tr[now]+=(LL)v*(r-l+1);
		delta[now]+=v;
		return;
	}
	pushdown(now,l,r);
	int mid=(l+r)/2;
	if (ll<=mid) change(now<<1,l,mid,ll,rr,v);
	if (rr>mid) change(now<<1|1,mid+1,r,ll,rr,v);
	tr[now]=tr[now<<1]+tr[now<<1|1];
}
void solve(int x,int y,LL v)
{
	while (belong[x]!=belong[y])
	 {
	 	if (deep[belong[x]]deep[y]) swap(x,y);
	change(1,1,n,pos[x],pos[y],v);
}
int main() 
{
	freopen("a.in","r",stdin);
	scanf("%d",&n);
	for (int i=1;i


你可能感兴趣的:(树链剖分)