Description
一个社交网站有nn个网页,第个公司拥有第ii个网页,每一个网页有一个父网页,不允许网页是jj网页的父网页且网页是ii网页的父网页,也不允许网页是自己的父网页,对于ii网页,设其父网页是网页,其子网页为j1,j2,...,jkj1,j2,...,jk,当用户浏览ii网页时,他们会看到来自家公司i,j0,j1,...,jki,j0,j1,...,jk的广告,有titi个用户喜欢第ii个网页,他们每个人都会点开一个广告看,对于家公司j0,j1,...,jkj0,j1,...,jk,会有⌊tik+2⌋⌊tik+2⌋个用户点开他们家的广告,对于剩下的ti−(k+1)⌊tik+2⌋ti−(k+1)⌊tik+2⌋个用户,他们会点开第ii家公司的广告。一个公司的总收入等于看他们家广告的用户数量。现在给出第个网页的父网页fifi,有qq个操作,操作分三种:
:第ii个网页的父网页变成,保证之前第ii个网页的父网页不是
2 i2 i:查询第ii家公司的总收入
:输出这nn家公司的最少收入和最多收入
Input
第一行两整数和qq分别表示公司数量和操作数量,之后输入个整数t1,...,tnt1,...,tn表示喜欢第ii个网页的用户数量,之后输入个整数f1,...,fnf1,...,fn表示第ii个网页的父网页,最后行每行一个操作(3≤n≤105,1≤q≤105,1≤ti≤1012)(3≤n≤105,1≤q≤105,1≤ti≤1012)
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
Solution
对每个节点xx用一个维护其儿子节点,维护儿子节点数量num[x]num[x],维护该节点其所有儿子节点对它的贡献之和ans[x]ans[x],那么一个节点的总收入为ans[x]ans[x]+f[x]f[x]对xx的贡献
总收入的最值必然是某个节点的儿子达到的,故开一个维护每个节点的儿子节点最值+自身对儿子的贡献,即为儿子真实总收入最值
对于11操作,假设的父亲由f[x]f[x]变成yy,那么值改变的最多只有x,f[x],f[f[x]],y,f[y]x,f[x],f[f[x]],y,f[y],对应的要把其父亲节点的儿子节点最值从SS中删掉,修改对应的值后再把这些点的父亲节点的儿子节点最值插入到SS中完成修改,注意这些点可能有重复,重复的点只需修改一次
对于操作,只需要输出ans[x]ans[x]+f[x]f[x]对xx的贡献即为节点的真实总收入
对于33操作,从中选出最值即可
Code
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<ctime>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
#define maxn 1000005
multiset<ll>S;
int n,q,p[maxn];
ll t[maxn],ans[maxn];
struct cmp
{
bool operator()(int a,int b)
{
if(ans[a]!=ans[b])return ans[a]<ans[b];
return a<b;
}
};
//set<int,cmp>::iterator it;
struct node
{
int num;//儿子节点的数量
set<int,cmp>s;
vector<ll> get()//取出儿子中最小值和最大值
{
vector<ll>v;
if(!s.empty())v.push_back(ans[*s.begin()]);
if(s.size()>=2)
{
auto it=s.end();
it--;
v.push_back(ans[*it]);
}
return v;
}
void insert(int a)
{
s.insert(a);
}
void erase(int a)
{
s.erase(a);
}
}f[maxn];
ll other(int a)
{
return t[a]/(2+f[a].num);
}
ll self(int a)
{
return t[a]-(1+f[a].num)*other(a);
}
int main()
{
scanf("%d%d",&n,&q);
for(int i=1;i<=n;i++)scanf("%I64d",&t[i]);
for(int i=1;i<=n;i++)
{
scanf("%d",&p[i]);
f[p[i]].num++,f[p[i]].insert(i);
}
for(int i=1;i<=n;i++)
{
//必须要先删掉i再插入i,因为ans[i]的值已经改变,其在set中的位置也应改变
f[p[i]].erase(i);
ans[i]=self(i);
for(int x:f[i].s)ans[i]+=other(x);
f[p[i]].insert(i);
}
for(int i=1;i<=n;i++)
{
vector<ll> V=f[i].get();
for(ll v:V)S.insert(v+other(i));
}
//for(int i=1;i<=n;i++)printf("%I64d ",ans[i]+other(p[i]));
while(q--)
{
int op;
scanf("%d",&op);
if(op==1)
{
int a,b;
scanf("%d%d",&a,&b);
set<int>update=set<int>{a,p[a],p[p[a]],b,p[b]};
set<int>update1=update;
for(int x:update)update1.insert(p[x]);
for(int x:update1)
{
vector<ll> V=f[x].get();
for(ll v:V)
{
auto it=S.find(v+other(x));
if(it!=S.end())S.erase(it);
}
}
for(int x:update)f[p[x]].erase(x);
for(int state=-1;state<=1;state+=2)
{
for(int x:update)
{
ans[x]+=state*self(x);
for(int y:update)
if(p[y]==x)ans[x]+=state*other(y);
}
if(state==-1)
f[p[a]].num--,p[a]=b,f[b].num++;
}
for(int x:update)f[p[x]].insert(x);
for(int x:update1)
{
vector<ll> V=f[x].get();
for(ll v:V)S.insert(v+other(x));
}
}
else if(op==2)
{
int a;
scanf("%d",&a);
printf("%I64d\n",ans[a]+other(p[a]));
}
else
{
printf("%I64d ",*S.begin());
auto it=S.end();
it--;
printf("%I64d\n",*it);
}
}
return 0;
}