ACM-ICPC 2018 焦作賽區網絡預賽 E. Jiu Yuan Wants to Eat
阿新 • • 發佈:2018-09-15
pan 解法 swap 焦作 inline 另一個 out else long long
分析
除了樹剖沒想到其他解法。
用線段樹維護區間和,同時針對修改區間修改操作建立兩個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; }
ACM-ICPC 2018 焦作賽區網絡預賽 E. Jiu Yuan Wants to Eat