CF643D Bearish Fanpages 題解
阿新 • • 發佈:2021-10-09
Link.
Description.
有一棵奇環內向數,第 \(i\) 個點指向 \(f_i\)。
每個點有一個權值 \(t_i\),\(\deg_x\) 表示的是它父親和兒子總數。
第 \(x\) 個點的價值是 \(\left\lceil\frac{t_x}{\deg_x+1}\right\rceil+\sum_{f_x=y\lor f_y=x}\left\lfloor\frac{t_y}{\deg_y+1}\right\rfloor\)
你需要維護它,支援
- 改變一個點的父親,即 \(f_x\rightarrow y\)。
- 計算第 \(i\) 個點的價值
- 計算當前所有點的最大價值和最小价值
Solution.
發現修改會影響它父親和它父親周圍的所有點,很難處理。
想到了根號分治,按照 \(\deg\) 分治,但是不夠優秀。
經典套路,我們在一個點父親處維護它的權值。
每次單獨算它父親對它貢獻權值。
這樣每個點改變會只會影響它在它父親、它父親在它父親父親、它父親在它父親的父親的父親的值。
是 \(O(1)\) 個數,可以直接用 multiset
暴搞。
至於操作 3,我們再維護兩個 multiset
表示每個 multiset
的最大值和最小值。
每次單點修改即可。
總複雜度 \(O(n\log n)\)。
Coding.
點選檢視程式碼
//是啊,你就是那隻鬼了,所以被你碰到以後,就輪到我變成鬼了{{{ #include<bits/stdc++.h> using namespace std;typedef long long ll; template<typename T>inline void read(T &x) { x=0;char c=getchar(),f=0; for(;c<48||c>57;c=getchar()) if(!(c^45)) f=1; for(;c>=48&&c<=57;c=getchar()) x=(x<<1)+(x<<3)+(c^48); f?x=-x:x; } template<typename T,typename...L>inline void read(T &x,L&...l) {read(x),read(l...);}//}}} const int N=100005;ll t[N],vl[N];char vs[N]; multiset<ll>st[N],sx,sn;int f[N],n,Q,dg[N]; inline void del(int x) { if(vs[x]||st[x].empty()) return;else vs[x]=1; sx.erase(sx.find(*--st[x].end()+t[x]/(dg[x]+1))); sn.erase(sn.find(*st[x].begin()+t[x]/(dg[x]+1))); } inline void add(int x) { if(!vs[x]||st[x].empty()) return;else vs[x]=0; sx.insert(*--st[x].end()+t[x]/(dg[x]+1)); sn.insert(*st[x].begin()+t[x]/(dg[x]+1)); } inline void work(int u,int y) { int x=f[u],fx=f[x],ffx=f[fx],fy=f[y],ffy=f[fy]; del(x),del(fx),del(ffx),del(y),del(fy),del(ffy); st[x].erase(st[x].find(vl[u])); st[fx].erase(st[fx].find(vl[x]));//x 少了個兒子,度減少 vl[x]-=t[u]/(dg[u]+1); vl[x]-=t[x]-t[x]/(dg[x]+1)*dg[x]; vl[x]+=t[x]-t[x]/dg[x]*(dg[x]-1); st[fx].insert(vl[x]); st[ffx].erase(st[ffx].find(vl[fx]));//fx 兒子貢獻減少 vl[fx]-=t[x]/(dg[x]+1),vl[fx]+=t[x]/dg[x]; st[ffx].insert(vl[fx]); dg[x]--,dg[y]++,f[u]=y,st[y].insert(vl[u]);//------------ st[fy].erase(st[fy].find(vl[y])); vl[y]+=t[u]/(dg[u]+1); vl[y]+=t[y]-t[y]/(dg[y]+1)*dg[y]; vl[y]-=t[y]-t[y]/dg[y]*(dg[y]-1); st[fy].insert(vl[y]); st[ffy].erase(st[ffy].find(vl[fy])); vl[fy]+=t[y]/(dg[y]+1),vl[fy]-=t[y]/dg[y]; st[ffy].insert(vl[fy]); add(x),add(fx),add(ffx),add(y),add(fy),add(ffy); } int main() { read(n,Q);for(int i=1;i<=n;i++) read(t[i]),dg[i]=1; for(int i=1;i<=n;i++) read(f[i]),dg[f[i]]++; for(int i=1;i<=n;i++) vl[i]+=t[i]-t[i]/(dg[i]+1)*dg[i]; for(int i=1;i<=n;i++) vl[f[i]]+=t[i]/(dg[i]+1); for(int i=1;i<=n;i++) st[f[i]].insert(vl[i]); for(int i=1;i<=n;i++) vs[i]=1,add(i); for(int i=1,fg,x,y;i<=Q;i++) { read(fg);if(fg==1) read(x,y),work(x,y); else if(fg==3) printf("%lld %lld\n",*sn.begin(),*--sx.end()); else read(x),printf("%lld\n",vl[x]+t[f[x]]/(dg[f[x]]+1)); //printf("?? %lld ; %lld : %lld\n",vl[4],t[f[4]],t[f[4]]/(dg[f[4]]+1)); }return 0; }