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