[HAOI2015]树上操作

  这是一道裸的树链剖分,但是15年HA好像还没有普及这个,连wmd神犇也是写的 O( n√n ) 的算法,还因为栈空间被卡到50分。

  但是不得不说HAOI2015的难度真的非常高,至少对我来说,而wmd即使这样也依然拿到了250分,实际上他应得350分,%%%。

  子树修改是一般的板子题不会有的操作,还是我对板子的认识有错误也有可能。

  根据第二次dfs的编号方式,可以发现,一颗子树中的所有节点编号也是连续的一段,这样就也把子树修改对应到区间修改了。

  我蛮久没写过树剖了。

  写好板子!

 

// q.c

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long LL;
const int M=100000+10;
int n,m,lable,w[M],fa[M],son[M],dep[M],size[M],id[M],top[M],pos[M],ch[M];
vector<int> G[M];
void dfs1(int u,int f,int d) {
	fa[u]=f,dep[u]=d,size[u]=1;
	for(int i=0,s=(int)G[u].size();i<s;i++) {
		int v=G[u][i];
		if(!fa[v]) {
			dfs1(v,u,d+1);
			if(size[v]>size[son[u]]||!son[u]) son[u]=v;
			size[u]+=size[v];
		}
	}
}
void dfs2(int u,int tp) {
	top[u]=tp,id[u]=ch[u]=++lable,pos[lable]=u;
	if(!son[u]) return ;
	dfs2(son[u],tp); ch[u]=max(ch[u],ch[son[u]]);
	for(int i=0,s=(int)G[u].size();i<s;i++) {
		int v=G[u][i];
		if(v!=fa[u]&&v!=son[u]) {
			dfs2(v,v);
			ch[u]=max(ch[u],ch[v]);
		}
	}
}
struct Node {
	int l,r; LL sum,lazy;
	Node():l(0),r(0),sum(0),lazy(0) {}
};
struct SegmentTree {
	Node nd[M<<2];
	void update(int o) {
		nd[o].sum=nd[o<<1].sum+nd[o<<1^1].sum;
	}
	void pushdown(int o) {
		nd[o<<1].sum+=nd[o].lazy*(nd[o<<1].r-nd[o<<1].l+1);
		nd[o<<1^1].sum+=nd[o].lazy*(nd[o<<1^1].r-nd[o<<1^1].l+1);
		nd[o<<1].lazy+=nd[o].lazy;
		nd[o<<1^1].lazy+=nd[o].lazy;
		nd[o].lazy=0;
	}
	void build(int o,int l,int r) {
		nd[o].l=l,nd[o].r=r;
		if(l==r) nd[o].sum=w[pos[l]];
		else {
			int mid=(l+r)>>1;
			build(o<<1,l,mid);
			build(o<<1^1,mid+1,r);
			update(o);
		}
	}
	void add(int o,int l,int r,int k) {
		if(l<=nd[o].l&&nd[o].r<=r) {
			nd[o].sum+=(LL)k*(nd[o].r-nd[o].l+1);
			nd[o].lazy+=k;
			return ;
		} else {
			if(nd[o].lazy) pushdown(o);
			int mid=(nd[o].l+nd[o].r)>>1;
			if(l<=mid) add(o<<1,l,r,k);
			if(r>mid) add(o<<1^1,l,r,k);
			update(o);
		}
	}
	LL query(int o,int l,int r) {
		if(l<=nd[o].l&&nd[o].r<=r) return nd[o].sum;
		else {
			if(nd[o].lazy) pushdown(o);
			LL ans=0; int mid=(nd[o].l+nd[o].r)>>1;
			if(l<=mid) ans+=query(o<<1,l,r);
			if(r>mid) ans+=query(o<<1^1,l,r);
			return ans;
		}
	}
}t;
void Add1(int a,int b) {
	t.add(1,id[a],id[a],b);
}
void Add2(int a,int b) {
	t.add(1,id[a],ch[a],b);
}
LL Query(int a,int b) {
	LL ans=0;
	while(top[a]!=top[b]) {
		if(dep[top[a]]<dep[top[b]]) swap(a,b);
		ans+=t.query(1,id[top[a]],id[a]);
		a=fa[top[a]];
	}
	if(dep[a]>dep[b]) swap(a,b);
	return ans+t.query(1,id[a],id[b]);
}
int main() {
	freopen("haoi2015_t2.in","r",stdin);
	freopen("haoi2015_t2.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%d",&w[i]);
	int opt,x,a,b;
	for(int i=1;i<n;i++) {
		scanf("%d%d",&a,&b);
		G[a].push_back(b);
		G[b].push_back(a);
	}
	dfs1(1,-1,0),dfs2(1,1),t.build(1,1,n);
	for(int i=1;i<=m;i++) {
		scanf("%d",&opt);
		if(opt==1) scanf("%d%d",&x,&a),Add1(x,a);
		else if(opt==2) scanf("%d%d",&x,&a),Add2(x,a);
		else scanf("%d",&x),printf("%lld\n",Query(1,x));
	}
	return 0;
}

 

posted @ 2018-04-15 20:33  qjs12  阅读(97)  评论(0编辑  收藏  举报