ACM-ICPC 2018 焦作赛区网络预赛 E. Jiu Yuan Wants to Eat


分析

除了树剖没想到其他解法。
用线段树维护区间和,同时针对修改区间修改操作建立两个lazy标记,一个是\(lazy_{mul}\),另一个是\(lazy_{add}\),代表区间里的数都需要先乘以\(lazy_{mul}\),再加上\(lazy_{add}\)。如果一个区间需要被重复标记,那么我们可以先把新的lazy标记施加在原有的lazy上。
如果是区间乘以val,那么就可以$ lazy_{mul}=lazy_{mul} \times val,lazy_{add}=lazy_{add}\times val $
对于区间取反操作可以转化成区间乘以-1,然后区间加上\(2^{64}-1\)

代码

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
const ll Mask=-1;
const int maxn=100050;
vector<int> G[maxn];
int sz[maxn],son[maxn],top[maxn],fa[maxn];
int dep[maxn];
void dfs(int x,int par) {
	sz[x]=1;
	fa[x]=par;
	for(auto y:G[x]) {
		if(y!=par) {
			dfs(y,x),sz[x]+=sz[y];
			if(son[x]==0||sz[y]>sz[son[x]]) son[x]=y;
		}
	}
}
int L[maxn],R[maxn],idx[maxn],tot;
void dfs2(int x,int par,int Top) {
	dep[x]=dep[par]+1;
	L[x]=++tot;
	idx[tot]=x;
	top[x]=Top;
	if(son[x]) dfs2(son[x],x,Top);
	for(auto y:G[x]) {
		if(y!=par && y!=son[x]) {
			dfs2(y,x,y);
		}
	}
	R[x]=tot;
}
ll sum[maxn*4],lazy_mul[maxn*4],lazy_add[maxn*4],wid[maxn*4];
void build(int l,int r,int id) {
	lazy_mul[id]=1,lazy_add[id]=0;
	wid[id]=r-l+1;
	sum[id]=0;
	if(l==r) return;
	int mid=(l+r)>>1;
	build(l,mid,id<<1);
	build(mid+1,r,id<<1|1);
}
void pushDown(int id) {
	if(wid[id]==1) {
		lazy_mul[id]=1,lazy_add[id]=0;
		return;
	}
	if(lazy_mul[id]==1&&lazy_add[id]==0) return;
	int x=(id<<1);
	lazy_mul[x]*=lazy_mul[id];
	lazy_add[x]*=lazy_mul[id];
	lazy_add[x]+=lazy_add[id];
	sum[x]=sum[x]*lazy_mul[id]+(lazy_add[id]*wid[x]);

	x=(id<<1|1);
	lazy_mul[x]*=lazy_mul[id];
	lazy_add[x]*=lazy_mul[id];
	lazy_add[x]+=lazy_add[id];
	sum[x]=sum[x]*lazy_mul[id]+(lazy_add[id]*wid[x]);
	lazy_mul[id]=1;
	lazy_add[id]=0;
}
void pushUp(int id) {
	sum[id]=sum[id<<1]+sum[id<<1|1];
}
void mul_update(int x,int y,ll val,int l,int r,int id) {
	pushDown(id);
	if(x<=l && y>=r) {
		lazy_mul[id]*=val;
		lazy_add[id]*=val;
		sum[id]*=val;
		return;
	}
	int mid=(l+r)>>1;
	if(x<=mid) mul_update(x,y,val,l,mid,id<<1);
	if(y>mid) mul_update(x,y,val,mid+1,r,id<<1|1);
	pushUp(id);
}
void add_update(int x,int y,ll val,int l,int r,int id) {
	pushDown(id);
	if(x<=l && y>=r) {
		lazy_add[id]+=val;
		sum[id]+=val*wid[id];
		return;
	}
	int mid=(l+r)>>1;
	if(x<=mid) add_update(x,y,val,l,mid,id<<1);
	if(y>mid) add_update(x,y,val,mid+1,r,id<<1|1);
	pushUp(id);
}
ll query(int x,int y,int l,int r,int id) {
	// cout<<l<<" "<<r<<" "<<sum[id]<<endl;
	pushDown(id);
	if(x<=l && y>=r) {
		//cout<<"in!\n";
		return sum[id];
	}
	int mid=(l+r)>>1;
	ll ans=0;
	if(x<=mid) /*(cout<<"go left\n",*/ ans+=query(x,y,l,mid,id<<1);
	if(y>mid) /*cout<<"go right\n",*/ ans+=query(x,y,mid+1,r,id<<1|1);
	return ans;
}
int main() {
	int n,q;
	while(scanf("%d", &n)!=EOF) {
		build(1,n,1);
		for(int i = 1; i <= n; ++i) G[i].clear(),sz[i]=top[i]=son[i]=0;
		for(int i = 2; i <= n; ++i) {
			int x;
			scanf("%d", &x);
			G[x].push_back(i);
		}
		scanf("%d", &q);
		tot=0;
		dfs(1,1);
		dfs2(1,1,1);
		while(q--) {
			int t,x,y;
			scanf("%d%d%d", &t,&x,&y);
			ll val;
			if(t==1) {
				scanf("%llu", &val);
				while(top[x]!=top[y]) {
					if(dep[top[x]]<dep[top[y]]) swap(x,y);
					mul_update(L[top[x]],L[x],val,1,n,1);
					x=fa[top[x]];
				}
				if(L[x]>L[y]) swap(x,y);
				mul_update(L[x],L[y],val,1,n,1);
			}
			else if(t==2) {
				scanf("%llu", &val);
				while(top[x]!=top[y]) {
					if(dep[top[x]]<dep[top[y]]) swap(x,y);
					add_update(L[top[x]],L[x],val,1,n,1);
					x=fa[top[x]];
				}
				if(L[x]>L[y]) swap(x,y);
				add_update(L[x],L[y],val,1,n,1);
			}
			else if(t==3) {
				while(top[x]!=top[y]) {
					if(dep[top[x]]<dep[top[y]]) swap(x,y);
					mul_update(L[top[x]],L[x],-1,1,n,1);
					add_update(L[top[x]],L[x],-1,1,n,1);
					x=fa[top[x]];
				}
				if(L[x]>L[y]) swap(x,y);
				mul_update(L[x],L[y],-1,1,n,1);
				add_update(L[x],L[y],-1,1,n,1);
			}
			else {
				ll ans=0;
				while(top[x]!=top[y]) {
					if(dep[top[x]]<dep[top[y]]) swap(x,y);
					ans+=query(L[top[x]],L[x],1,n,1);
					x=fa[top[x]];
				}
				if(L[x]>L[y]) swap(x,y);
				ans+=query(L[x],L[y],1,n,1);
				printf("%llu\n", ans);
			}
		}
	}
	return 0;
}
posted @ 2018-09-15 20:54  sciorz  阅读(173)  评论(0编辑  收藏  举报