Description
一个社交网站有 n n 个网页,第个公司拥有第 i i 个网页,每一个网页有一个父网页,不允许网页是 j j 网页的父网页且网页是 i i 网页的父网页,也不允许网页是自己的父网页,对于 i i 网页,设其父网页是网页,其子网页为 j1,j2,...,jk j 1 , j 2 , . . . , j k ,当用户浏览 i i 网页时,他们会看到来自家公司 i,j0,j1,...,jk i , j 0 , j 1 , . . . , j k 的广告,有 ti t i 个用户喜欢第 i i 个网页,他们每个人都会点开一个广告看,对于家公司 j0,j1,...,jk j 0 , j 1 , . . . , j k ,会有 ⌊tik+2⌋ ⌊ t i k + 2 ⌋ 个用户点开他们家的广告,对于剩下的 ti−(k+1)⌊tik+2⌋ t i − ( k + 1 ) ⌊ t i k + 2 ⌋ 个用户,他们会点开第 i i 家公司的广告。一个公司的总收入等于看他们家广告的用户数量。现在给出第个网页的父网页 fi f i ,有 q q 个操作,操作分三种:
:第 i i 个网页的父网页变成,保证之前第 i i 个网页的父网页不是
2 i 2 i :查询第 i i 家公司的总收入
:输出这 n n 家公司的最少收入和最多收入
Input
第一行两整数和 q q 分别表示公司数量和操作数量,之后输入个整数 t1,...,tn t 1 , . . . , t n 表示喜欢第 i i 个网页的用户数量,之后输入个整数 f1,...,fn f 1 , . . . , f n 表示第 i i 个网页的父网页,最后行每行一个操作 (3≤n≤105,1≤q≤105,1≤ti≤1012) ( 3 ≤ n ≤ 10 5 , 1 ≤ q ≤ 10 5 , 1 ≤ t i ≤ 10 12 )
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
对每个节点 x x 用一个维护其儿子节点,维护儿子节点数量 num[x] n u m [ x ] ,维护该节点其所有儿子节点对它的贡献之和 ans[x] a n s [ x ] ,那么一个节点的总收入为 ans[x] a n s [ x ] + f[x] f [ x ] 对 x x 的贡献
总收入的最值必然是某个节点的儿子达到的,故开一个维护每个节点的儿子节点最值+自身对儿子的贡献,即为儿子真实总收入最值
对于 1 1 操作,假设的父亲由 f[x] f [ x ] 变成 y y ,那么值改变的最多只有 x,f[x],f[f[x]],y,f[y] x , f [ x ] , f [ f [ x ] ] , y , f [ y ] ,对应的要把其父亲节点的儿子节点最值从 S S 中删掉,修改对应的值后再把这些点的父亲节点的儿子节点最值插入到 S S 中完成修改,注意这些点可能有重复,重复的点只需修改一次
对于操作,只需要输出 ans[x] a n s [ x ] + f[x] f [ x ] 对 x x 的贡献即为节点的真实总收入
对于 3 3 操作,从中选出最值即可
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;
}