ACM-ICPC 2018 焦作賽區網絡預賽 E. Jiu Yuan Wants to Eat (樹鏈剖分-線性變換線段樹)
阿新 • • 發佈:2018-09-15
online top splay 線段樹 clas mes bits amp play
樹鏈剖分若不會的話可自行學習一下.
前兩種操作是線性變換,模\(2^{64}\)可將線段樹全部用unsigned long long 保存,另其自然溢出.
而取反操作比較不能直接處理,因為其模\(2^{64}\)的特殊性,可將其轉化為線性變換.
顯然
\[-x\equiv (2^{64}-1)*x (mod\ 2^{64})\]
因為\[!x = (2^{64}-1) -x \]
所以
\[ !x = (2^{64}-1) + (2^{64}-1)x\]
#include<bits/stdc++.h> #define lson rt<<1 #define rson rt<<1|1 #define Lson l,m,lson #define Rson m+1,r,rson typedef unsigned long long LL; LL TTT = 0xffffffffffffffff; using namespace std; const int maxn =1e5+5; struct Edge{ int to,next; }E[2*maxn]; int n,head[maxn],tot; int cnt,idx,size[maxn],fa[maxn],son[maxn],dep[maxn],top[maxn],id[maxn],rnk[maxn]; void init() { cnt=idx=tot=0; memset(head,-1,sizeof(head)); dep[1]=0,fa[1]=1,size[0]=0; memset(son,0,sizeof(son)); } void AddEdge(int u,int v) { E[tot] = (Edge){v,head[u]}; head[u]=tot++; } void dfs1(int u) { size[u]=1; for(int i=head[u];~i;i=E[i].next){ int v=E[i].to; if(v!=fa[u]){ fa[v]=u; dep[v]=dep[u]+1; dfs1(v); size[u]+=size[v]; if(size[son[u]]<size[v]) son[u]=v; } } } void dfs2(int u,int topu) { top[u]= topu; id[u] = ++idx; rnk[idx] = u; if(!son[u]) return; dfs2(son[u],top[u]); for(int i=head[u];~i;i=E[i].next){ int v=E[i].to; if(v!=fa[u]&&v!=son[u]) dfs2(v,v); } } struct Node{ LL sum,add,b; bool nt; }tree[maxn<<2]; void pushup(int rt){ tree[rt].sum = tree[lson].sum + tree[rson].sum; } void pushdown(int l,int r,int rt) { int m = (l+r)>>1; if(tree[rt].add!=1){ tree[lson].sum *= tree[rt].add; tree[rson].sum *= tree[rt].add; tree[lson].b *= tree[rt].add; tree[rson].b *= tree[rt].add; tree[lson].add *= tree[rt].add; tree[rson].add *= tree[rt].add; tree[rt].add = 1; } if(tree[rt].b){ tree[lson].sum += (m-l+1)* tree[rt].b; tree[rson].sum += (r-m) *tree[rt].b; tree[lson].b += tree[rt].b; tree[rson].b += tree[rt].b; tree[rt].b= 0; } } void build(int l,int r,int rt) { tree[rt].add =1; tree[rt].b =0; tree[rt].nt = 0; if(l==r){ tree[rt].sum = 0; return; } int m = (l+r)>>1; build(Lson); build(Rson); pushup(rt); } void update(int L,int R,LL k,LL b,int l=1,int r=n,int rt=1) { if(L<=l && R>=r){ tree[rt].sum *= k; tree[rt].add *= k; tree[rt].b *= k; tree[rt].sum += (r-l+1)*b; tree[rt].b +=b; tree[rt].nt = 0; return; } pushdown(l,r,rt); int m = (l+r)>>1; if(L<=m) update(L,R,k,b,Lson); if(R>m) update(L,R,k,b,Rson); pushup(rt); } LL query(int L,int R,int l=1,int r= n,int rt=1) { if(L<=l && R>=r){ return tree[rt].sum; } pushdown(l,r,rt); LL ans=0; int m = (l+r)>>1; if(L<=m) ans += query(L,R,Lson); if(R>m) ans += query(L,R,Rson); return ans; } void change(int u,int v,int op,LL val) { while(top[u]!=top[v]){ if(dep[top[u]]<dep[top[v]]) swap(u,v); if(op==1){ update(id[top[u]],id[u],(LL)1,val); } else if(op==2){ update(id[top[u]],id[u],val,0); } else{ update(id[top[u]],id[u],TTT,TTT); } u = fa[top[u]]; } if(dep[u]>dep[v]) swap(u,v); if(op==1){ update(id[u],id[v],(LL)1,val); } else if(op==2){ update(id[u],id[v],val,0); } else{ update(id[u],id[v],TTT,TTT); } return ; } LL Qsum(int u,int v) { LL ans=0; while(top[u]!=top[v]){ if(dep[top[u]]<dep[top[v]]) swap(u,v); ans += query(id[top[u]],id[u]); u = fa[top[u]]; } if(dep[u]>dep[v]) swap(u,v); ans += query(id[u],id[v]); return ans; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); freopen("out.txt","w",stdout); #endif int u,v,Q; while(scanf("%d",&n)==1){ init(); for(int i=2;i<=n;++i){ scanf("%d",&u); AddEdge(u,i); AddEdge(i,u); } dfs1(1); dfs2(1,1); build(1,n,1); scanf("%d",&Q); int op; LL tmp; while(Q--){ scanf("%d",&op); if(op==1){ scanf("%d %d %lld",&u, &v, &tmp); change(u,v,2,tmp); } else if(op==2){ scanf("%d %d %llu",&u, &v,&tmp); change(u,v,1,tmp); } else if(op==3){ scanf("%d %d",&u, &v); change(u,v,3,0); } else{ scanf("%d %d",&u, &v); printf("%llu\n",Qsum(u,v)); } } } return 0; }
ACM-ICPC 2018 焦作賽區網絡預賽 E. Jiu Yuan Wants to Eat (樹鏈剖分-線性變換線段樹)