Description
Input
Output
Sample Input
5 12
10 20 30 40 50
2 3 4 5 2
2 1
2 2
2 3
2 4
2 5
1 4 2
2 1
2 2
2 3
2 4
2 5
3
Sample Output
10
36
28
40
36
9
57
27
28
29
9 57
Data Constraint
Solution
-
我們把 稱作 的“父親”,而所有滿足 的 稱作 的“兒子”。
-
觀察到每個點只有 這一個父親,這是一個突破口。
-
一開始時的 我們是可以直接求出的,現在考慮快速維護 。
-
可以發現我們只需要一個不加上父親權值的 就很好維護了。
-
於是一個點 的 。
-
那麼修改的時候只需要在幾個點上對 和 加加減減即可,
-
這個細節比較多(其實不算多了,下面更……),但很容易就做到 進行操作1、2了。
-
接下來就是操作3了——回答全局 的最值。
-
這個很自然會想到用 set 來維護。
-
具體來說就是,對每個點維護一個存其兒子的 的 set 。
-
之後全局再維護一個存所有 的 set ,不過這個可以將每個點的 set 中取最大最小值扔進去就夠了。
-
很“顯然”我們可以在一次修改中 地修改完所有 set 。。(細節巨多,無法描述。。)
-
那麼我們直接從全局 set 取出最值就可以回答詢問3了。
-
總時間複雜度 。
-
強烈建議在修改 set 的時候打成一個過程(要調用很多次),不然展開打就會像我的代碼一樣與臭又長……
Code
#include<cstdio>
#include<set>
#include<cctype>
using namespace std;
typedef long long LL;
const int N=1e5+5;
int a[N],d[N];
LL b[N],c[N];
multiset<LL>ss[N],val;
multiset<LL>::iterator it;
inline int read()
{
int X=0,w=0; char ch=0;
while(!isdigit(ch)) w|=ch=='-',ch=getchar();
while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
return w?-X:X;
}
int main()
{
freopen("forest.in","r",stdin);
freopen("forest.out","w",stdout);
int n=read(),q=read();
for(int i=1;i<=n;i++) scanf("%lld",&b[i]);
for(int i=1;i<=n;i++)
{
a[i]=read();
d[i]+=2;
d[a[i]]++;
}
for(int i=1;i<=n;i++)
{
c[i]+=b[i]%d[i]+b[i]/d[i];
c[a[i]]+=b[i]/d[i];
}
for(int i=1;i<=n;i++) ss[a[i]].insert(c[i]);
for(int i=1;i<=n;i++)
if(!ss[i].empty())
{
val.insert(*ss[i].begin()+b[i]/d[i]);
val.insert(*ss[i].rbegin()+b[i]/d[i]);
}
while(q--)
{
int ty=read();
if(ty==1)
{
int x=read(),y=read(),z=a[x];
if(y==z) continue;
if(!ss[z].empty())
{
it=val.find(*ss[z].begin()+b[z]/d[z]);
if(it!=val.end()) val.erase(it);
it=val.find(*ss[z].rbegin()+b[z]/d[z]);
if(it!=val.end()) val.erase(it);
}
if(!ss[y].empty())
{
it=val.find(*ss[y].begin()+b[y]/d[y]);
if(it!=val.end()) val.erase(it);
it=val.find(*ss[y].rbegin()+b[y]/d[y]);
if(it!=val.end()) val.erase(it);
}
ss[z].erase(ss[z].find(c[x]));
ss[y].insert(c[x]);
LL mn=*ss[a[z]].begin(),mx=*ss[a[z]].rbegin();
ss[a[z]].erase(ss[a[z]].find(c[z]));
c[z]+=b[z]%(d[z]-1)-b[z]%d[z]-b[x]/d[x]+b[z]/(d[z]-1)-b[z]/d[z];
ss[a[z]].insert(c[z]);
LL num=*ss[a[z]].begin();
if(num^mn)
{
it=val.find(mn+b[a[z]]/d[a[z]]);
if(it!=val.end())
{
val.erase(it);
val.insert(num+b[a[z]]/d[a[z]]);
}
}
num=*ss[a[z]].rbegin();
if(num^mx)
{
it=val.find(mx+b[a[z]]/d[a[z]]);
if(it!=val.end())
{
val.erase(it);
val.insert(num+b[a[z]]/d[a[z]]);
}
}
mn=*ss[a[a[z]]].begin(),mx=*ss[a[a[z]]].rbegin();
ss[a[a[z]]].erase(ss[a[a[z]]].find(c[a[z]]));
c[a[z]]+=b[z]/(d[z]-1)-b[z]/d[z];
ss[a[a[z]]].insert(c[a[z]]);
num=*ss[a[a[z]]].begin();
if(num^mn)
{
it=val.find(mn+b[a[a[z]]]/d[a[a[z]]]);
if(it!=val.end())
{
val.erase(it);
val.insert(num+b[a[a[z]]]/d[a[a[z]]]);
}
}
num=*ss[a[a[z]]].rbegin();
if(num^mx)
{
it=val.find(mx+b[a[a[z]]]/d[a[a[z]]]);
if(it!=val.end())
{
val.erase(it);
val.insert(num+b[a[a[z]]]/d[a[a[z]]]);
}
}
d[z]--;
a[x]=y;
mn=*ss[a[y]].begin(),mx=*ss[a[y]].rbegin();
ss[a[y]].erase(ss[a[y]].find(c[y]));
c[y]+=b[y]%(d[y]+1)-b[y]%d[y]+b[x]/d[x]+b[y]/(d[y]+1)-b[y]/d[y];
ss[a[y]].insert(c[y]);
num=*ss[a[y]].begin();
if(num^mn)
{
it=val.find(mn+b[a[y]]/d[a[y]]);
if(it!=val.end())
{
val.erase(it);
val.insert(num+b[a[y]]/d[a[y]]);
}
}
num=*ss[a[y]].rbegin();
if(num^mx)
{
it=val.find(mx+b[a[y]]/d[a[y]]);
if(it!=val.end())
{
val.erase(it);
val.insert(num+b[a[y]]/d[a[y]]);
}
}
mn=*ss[a[a[y]]].begin(),mx=*ss[a[a[y]]].rbegin();
ss[a[a[y]]].erase(ss[a[a[y]]].find(c[a[y]]));
c[a[y]]+=b[y]/(d[y]+1)-b[y]/d[y];
ss[a[a[y]]].insert(c[a[y]]);
num=*ss[a[a[y]]].begin();
if(num^mn)
{
it=val.find(mn+b[a[a[y]]]/d[a[a[y]]]);
if(it!=val.end())
{
val.erase(it);
val.insert(num+b[a[a[y]]]/d[a[a[y]]]);
}
}
num=*ss[a[a[y]]].rbegin();
if(num^mx)
{
it=val.find(mx+b[a[a[y]]]/d[a[a[y]]]);
if(it!=val.end())
{
val.erase(it);
val.insert(num+b[a[a[y]]]/d[a[a[y]]]);
}
}
d[y]++;
if(!ss[z].empty())
{
val.insert(*ss[z].begin()+b[z]/d[z]);
val.insert(*ss[z].rbegin()+b[z]/d[z]);
}
if(!ss[y].empty())
{
val.insert(*ss[y].begin()+b[y]/d[y]);
val.insert(*ss[y].rbegin()+b[y]/d[y]);
}
}else
if(ty==2)
{
int x=read();
printf("%lld\n",c[x]+b[a[x]]/d[a[x]]);
}else
{
printf("%lld %lld\n",*val.begin(),*val.rbegin());
}
}
return 0;
}