【bzoj2836】【魔法树】【树链剖分】

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
题解:裸链剖各种写残真是没治了。。
代码:
#include<iostream>
#include<cstdio>
#define N 100010
#define LL long long
using namespace std;
int point[N],next[N*2],cnt,f[N][20],n,x,y,kind,deep[N],size[N],mn[N];
int be[N],pos[N],tt,temp,q;
char ch[10];
LL t[N*4],p[N*4],v;
struct use{int st,en;}e[N*2]; 
void add(int x,int y){
  next[++cnt]=point[x];point[x]=cnt;
  e[cnt].st=x;e[cnt].en=y;
}
void dfs1(int x){
  size[x]=1;
  for (int i=1;i<=18;i++)
   if ((1<<i)>deep[x]) break;else f[x][i]=f[f[x][i-1]][i-1]; 
  for (int i=point[x];i;i=next[i])
  	 if (e[i].en!=f[x][0]){
  	 	f[e[i].en][0]=x;deep[e[i].en]=deep[x]+1;
		dfs1(e[i].en);size[x]+=size[e[i].en];
  	 }
}
void dfs2(int x,int c){
   mn[x]=pos[x]=++tt;be[x]=c;int k=0;
   for (int i=point[x];i;i=next[i]){
      if (size[k]<size[e[i].en]&&e[i].en!=f[x][0]) k=e[i].en;
   }	
   if (!k) return;dfs2(k,c);mn[x]=max(mn[x],mn[k]);
   for (int i=point[x];i;i=next[i])
   	  if (e[i].en!=f[x][0]&&e[i].en!=k){
	   dfs2(e[i].en,e[i].en);mn[x]=max(mn[x],mn[e[i].en]);
    }
}
int lca(int x,int y)  
{  
    int t;  
    if(deep[x]<deep[y]) swap(x,y);t=deep[x]-deep[y]; 
    for (int i=0;i<=18;i++) if (t&(1<<i)) x=f[x][i];  
     for (int i=18;i>=0;i--)  
       if (f[x][i]!=f[y][i]) {x=f[x][i];y=f[y][i];}  
     if (x==y) return x;else return f[x][0];  
}
void paint(int k,int l,int r,LL v){t[k]+=(LL)(r-l+1)*v;p[k]+=v;}
void pushdown(int k,int l,int r){
	int mid=(l+r)/2;
	paint(k*2,l,mid,p[k]);paint(k*2+1,mid+1,r,p[k]);
	p[k]=0;
}
void change(int k,int l,int r,int ll,int rr,LL v){
	int mid=(l+r)/2;
	if (ll<=l&&r<=rr){paint(k,l,r,v);return;}
	if (p[k]) pushdown(k,l,r);
	if (ll<=mid) change(k*2,l,mid,ll,rr,v);
	if (mid<rr) change(k*2+1,mid+1,r,ll,rr,v);
	t[k]=t[k*2]+t[k*2+1];
} 
LL query(int k,int l,int r,int ll,int rr){
	int mid=(l+r)/2;LL ans(0);
	if (ll<=l&&r<=rr) return t[k];
	if (p[k]) pushdown(k,l,r);
	if (ll<=mid) ans+=query(k*2,l,mid,ll,rr);
	if (rr>mid) ans+=query(k*2+1,mid+1,r,ll,rr);
	return ans;
}
void add(int x,int y,LL v){
   while (be[x]!=be[y]){change(1,1,n,pos[be[x]],pos[x],v);x=f[be[x]][0];}
   change(1,1,n,pos[y],pos[x],v);	
}
int main(){
	scanf("%d",&n);
	for (int i=1;i<=n-1;i++){scanf("%d%d",&x,&y);x++;y++;add(x,y);add(y,x);}
	dfs1(1);dfs2(1,1);scanf("%d",&q);
	for (int i=1;i<=q;i++){
	  scanf("%s",ch);
	  if (ch[0]=='A'){
	   scanf("%d%d%lld",&x,&y,&v);x++;y++;tt=lca(x,y);
	   add(x,tt,v);add(y,tt,v);add(tt,tt,-v);
	  }
	  if (ch[0]=='Q'){
	    scanf("%d",&x);x++;printf("%lld\n",query(1,1,n,pos[x],mn[x]));
	  }
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值