您的位置:首页 > 其它

CodeForces 674 D.Bearish Fanpages(set+multiset)

2017-08-27 15:42 513 查看
Description

一个社交网站有n个网页,第i个公司拥有第i个网页,每一个网页有一个父网页,不允许i网页是j网页的父网页且j网页是i网页的父网页,也不允许i网页是自己的父网页,对于i网页,设其父网页是j0网页,其子网页为j1,j2,...,jk,当用户浏览i网页时,他们会看到来自k+2家公司i,j0,j1,...,jk的广告,有ti个用户喜欢第i个网页,他们每个人都会点开一个广告看,对于k+1家公司j0,j1,...,jk,会有⌊tik+2⌋个用户点开他们家的广告,对于剩下的ti−(k+1)⌊tik+2⌋个用户,他们会点开第i家公司的广告。一个公司的总收入等于看他们家广告的用户数量。现在给出第i个网页的父网页fi,有q个操作,操作分三种:

1 i j:第i个网页的父网页变成j,保证之前第i个网页的父网页不是j

2 i:查询第i家公司的总收入

3:输出这n家公司的最少收入和最多收入

Input

第一行两整数n和q分别表示公司数量和操作数量,之后输入n个整数t1,...,tn表示喜欢第i个网页的用户数量,之后输入n个整数f1,...,fn表示第i个网页的父网页,最后q行每行一个操作(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

对每个节点x用一个set维护其儿子节点,维护儿子节点数量num[x],维护该节点其所有儿子节点对它的贡献之和ans[x],那么一个节点的总收入为ans[x]+f[x]对x的贡献

总收入的最值必然是某个节点的儿子达到的,故开一个multiset S维护每个节点的儿子节点最值+自身对儿子的贡献,即为儿子真实总收入最值

对于1操作,假设x的父亲由f[x]变成y,那么ans值改变的最多只有x,f[x],f[f[x]],y,f[y],对应的要把其父亲节点的儿子节点最值从S中删掉,修改对应的ans值后再把这些点的父亲节点的儿子节点最值插入到S中完成修改,注意这些点可能有重复,重复的点只需修改一次

对于2操作,只需要输出ans[x]+f[x]对x的贡献即为x节点的真实总收入

对于3操作,从S中选出最值即可

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: