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
一个社交网站有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; }
相关文章推荐
- Codeforces 527C Glass Carving<set集合和multiset集合的使用>
- CodeForces 527C - Glass Carving set multiset 二分
- CodeForces 527C:Glass Carving (set与multiset应用)
- Codeforces 527C Glass Carving (set+multiset)
- STL-------set与multiset
- STL容器 set、 multiset、map、multimap
- STL:set/multiset用法详解
- Using SiteMap and MasterPages to set META Tags in ASP.NET and C#
- set与multiset的用法
- C++:关联容器(set,multiset,map,multimap)
- codeforces 460D:Little Victor and Set
- Set & Multiset
- 解决办法:tomcat should be set in Tomcat Perferencr Pages
- CodeForces 356A_(set应用,线段树)
- set/multiset map/multimap hash_set/hash_multiset hash_map/hash_multimap 区别与联系
- codeforces 274A. k-Multiple Free Set【二分】
- std::set和multiset
- 【学习笔记】 关于 Set 和 Multiset
- CodeForces - 746F : Music in Car(set)
- Codeforces div.2 B. The Child and Set