[BZOJ4034] [HAOI2015] T2 - 树链剖分

总觉得这个树剖写得不爽 - -

这应该算树剖模板题吧qaq

(原来是zzt太弱了,这题直接线段树搞就可以了,继续%ydc

#include"bits/stdc++.h"
using namespace std;

typedef long long ll;
const int N=100005,LG=20;

vector<int>e[N];
int beg[N],n,dfn[N],bel[N],size[N],deep[N],val[N],fa[N][LG],cnt,m;

int lca(int x,int y){
	if(deep[x]<deep[y])swap(x,y);
	int dx=deep[x],dy=deep[y],l=dx-dy;
	for(int i=0;l;i++)if(l&(1<<i))x=fa[x][i],l^=(1<<i);
	for(int i=17;x!=y&&i>=0;i--)
		if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
	return x==y?x:fa[x][0];
}

void dfs1(int x){
	size[x]=1;
	for(int i=1;fa[x][i-1];fa[x][i]=fa[fa[x][i-1]][i-1],i++);
	for(int i=0;i<e[x].size();i++){
		int to=e[x][i];
		if(!deep[to]){
			deep[to]=deep[x]+1;
			fa[to][0]=x;dfs1(to);
			size[x]+=size[to];
		}
	}
}

void dfs2(int x,int b){
	bel[x]=b;dfn[x]=++cnt;
	val[cnt]=beg[x];int f=-1,siz=0;
	for(int i=0;i<e[x].size();i++)
		if(size[e[x][i]]>siz&&deep[e[x][i]]>deep[x])
			siz=size[e[x][i]],f=e[x][i];
	if(f==-1)return;dfs2(f,b);
	for(int i=0;i<e[x].size();i++)
		if(deep[e[x][i]]>deep[x]&&e[x][i]!=f)
			dfs2(e[x][i],e[x][i]);
}

ll sum[4*N],tag[4*N];

void build(int v,int l,int r){
	if(l==r){sum[v]=val[l];return;}
	int mid=(l+r)>>1,ls=v<<1,rs=ls|1;
	build(ls,l,mid);build(rs,mid+1,r);
	sum[v]=sum[ls]+sum[rs];
}

void pushdown(int v,int l,int r){
	if(l!=r)tag[v<<1]+=tag[v],tag[v<<1|1]+=tag[v];
	sum[v]+=(r-l+1)*tag[v];tag[v]=0;
}

void add(int v,int l,int r,int s,int t,int a){
	if(l==s&&r==t){tag[v]+=a;pushdown(v,l,r);return;}
	int mid=(l+r)>>1,ls=v<<1,rs=ls|1;pushdown(v,l,r);
	if(t<=mid)add(ls,l,mid,s,t,a);
	else if(s>mid)add(rs,mid+1,r,s,t,a);
	else add(ls,l,mid,s,mid,a),add(rs,mid+1,r,mid+1,t,a);
	pushdown(ls,l,mid);pushdown(rs,mid+1,r);
	sum[v]=sum[ls]+sum[rs];
}

ll qry(int v,int l,int r,int s,int t){
	pushdown(v,l,r);
	if(l==s&&r==t)return sum[v];
	int mid=(l+r)>>1,ls=v<<1,rs=ls|1;
	if(t<=mid)return qry(ls,l,mid,s,t);
	if(s>mid)return qry(rs,mid+1,r,s,t);
	return qry(ls,l,mid,s,mid)+qry(rs,mid+1,r,mid+1,t);
}

ll run(int fr,int to){
	ll re=0;
	while(bel[fr]!=bel[to]){
		re+=qry(1,1,n,dfn[bel[fr]],dfn[fr]);
		fr=fa[bel[fr]][0];
	}
	re+=qry(1,1,n,dfn[to],dfn[fr]);
	return re;
}

void work(){
	int x,y,f,i,ty;
	for(i=1;i<=m;i++){
		scanf("%d",&ty);
		if(ty<3){
			scanf("%d%d",&x,&y);
			if(ty==1)add(1,1,n,dfn[x],dfn[x],y);
			else add(1,1,n,dfn[x],dfn[x]+size[x]-1,y);
		} else{
			scanf("%d",&x);
			printf("%lld\n",run(x,1));
		}
	}
}

void pre(){
	int i,u,v,c;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++)
		scanf("%d",&beg[i]);
	for(i=1;i<n;i++){
		scanf("%d%d",&u,&v);
		e[u].push_back(v);
		e[v].push_back(u);
	}
	deep[1]=1;dfs1(1);dfs2(1,1);
	build(1,1,n);
}

int main(){
	pre();work();
	return 0;
} 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值