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;
}