[BZOJ4034][欧拉序]HAOI2015:树上操作

版权声明:虽然博主很菜,但是还是请注明出处(我觉得应该没人偷我的博客) https://blog.csdn.net/qq_43346903/article/details/88045944

BZOJ4034

这个树剖sb题我写什么呢?
欧拉序 o ( n l o g n ) o(nlogn)

欧拉序:一个点入栈的时候加入序列,成为左括号,出栈的时候再加入一次,成为右括号

修改就可以直接在欧拉序序列上修改

这里右括号保存与左括号符号相反的值,达到一个类似差分的目的

欧拉序要开两倍空间

Code:

#include<bits/stdc++.h>
#define rs tr[k].r
#define ls tr[k].l
#define mid ((ls+rs)>>1)
#define ll long long
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int N=2e5+5;
int n;
ll a[N];int pos[N*2];
ll work[N<<1];
namespace segtree{
	struct seg{int l,r;ll add,sum;}tr[N<<2];
	inline void pushup(int k){tr[k].sum=tr[k<<1].sum+tr[k<<1|1].sum;}
	inline void pushadd(int k,ll v){tr[k].add+=v;tr[k].sum+=((ll)pos[rs]-pos[ls-1])*v;}
	inline void pushdown(int k){if(tr[k].add){pushadd(k<<1,tr[k].add);pushadd(k<<1|1,tr[k].add);tr[k].add=0;}}
	void build(int k,int l,int r){
		ls=l,rs=r;tr[k].add=0;
		if(l==r) {tr[k].sum=(pos[ls]-pos[ls-1])*work[l];return;}
		build(k<<1,l,mid);build(k<<1|1,mid+1,r);
		pushup(k);
	}
	void modify(int k,int ql,int qr,ll v){
		if(ls>qr || rs<ql || ql>qr) return;
		if(ql<=ls && rs<=qr) return pushadd(k,v);
		pushdown(k);
		if(qr<=mid) modify(k<<1,ql,qr,v);
		else if(ql>mid) modify(k<<1|1,ql,qr,v);
		else modify(k<<1,ql,mid,v),modify(k<<1|1,mid+1,qr,v);
		pushup(k);
	}
	ll ask(int k,int ql,int qr){
		if(ls>qr || rs<ql) return 0;
		if(ql<=ls && rs<=qr) return tr[k].sum;
		pushdown(k);
		if(qr<=mid) return ask(k<<1,ql,qr);
		else if(ql>mid) return ask(k<<1|1,ql,qr);
		else return ask(k<<1,ql,mid)+ask(k<<1|1,mid+1,qr);	
	}
}
int m;
using namespace segtree;
int vis[N<<1],nxt[N<<1],head[N<<1],tot=0;
int l[N<<1],r[N<<1],cnt=0,pt[N];
inline void add(int x,int y){vis[++tot]=y;nxt[tot]=head[x];head[x]=tot;}
void dfs(int v){
	pt[v]=1;l[v]=++cnt;work[cnt]=a[v];pos[cnt]=1;
	for(int i=head[v];i;i=nxt[i]){
		if(pt[vis[i]]) continue;
		dfs(vis[i]);
	}
	r[v]=++cnt;work[cnt]=a[v];pos[cnt]=-1;
}
int main(){
	n=read();m=read();
	for(int i=1;i<=n;i++) a[i]=read();
	for(int x,y,i=1;i<n;i++) x=read(),y=read(),add(x,y),add(y,x);
	dfs(1);n*=2;
	for(int i=1;i<=n;i++) pos[i]+=pos[i-1];
	build(1,1,n);
	while(m--){
		int op=read();
		if(op==3) cout<<ask(1,1,l[read()])<<"\n";
		else{
			int x=read();ll v=(ll)read();
			if(op==1) modify(1,l[x],l[x],v),modify(1,r[x],r[x],v);
			else modify(1,l[x],r[x],v);
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43346903/article/details/88045944