1. 程式人生 > 其它 >CF643D Bearish Fanpages 題解

CF643D Bearish Fanpages 題解

Codeforces
Luogu

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