题面

题解

为了一点小细节卡了一个下午……我都怕我瞎用set把电脑搞炸……

观察一次\(1\)操作会造成什么影响,比如说把\(A[i]\)从\(x\)改成\(y\):

\(D[x]\)会\(-1\),导致\(E[x]=B[x]/D[x]\)会修改

\(D[y]\)会\(+1\),导致\(E[y]=B[y]/D[y]\)会修改

连边关系会修改

当某个\(E[x]\)改变时,所有跟它距离不超过\(1\)的点的\(C[]\)值都要修改

\(C[A[x]]\):单点修改

\(C[x]\):单点修改

儿子们的\(C[]\):打个标记

那么思路就明确了:对每个点搞个\(set\)维护它的儿子

修改单点的时候从父亲的\(set\)里拿出来,修改掉再插回去

对儿子整体修改的时候打标记

在全局再开两个\(set\),分别维护所有\(set\)最小值的最小值、最大值的最大值

断开/连接一条边的时候把标记的贡献算一下

以上是官方题解,这里说几个细节:

因为对于儿子们的\(C_i\),是所有的儿子和父亲的\(E_i\)之和加上一堆乱七八糟的东西,所以算儿子的\(C_i\)时可以不加上父亲的\(E_i\),等需要答案的时候再加上去,这样修改的时候可以直接更新父亲的\(E_i\)即可

最后,注意细节

//minamoto
#include<bits/stdc++.h>
#define R register
#define ll long long
#define IT multiset<ll>::iterator
#define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
char buf[1<<21],*p1=buf,*p2=buf;
inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
ll read(){
R ll res,f=1;R char ch;
while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
return res*f;
}
char sr[1<<21],z[20];int C=-1,Z=0;
inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;}
void print(R ll x){
if(C>1<<20)Ot();if(x<0)sr[++C]='-',x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=1e5+5;
ll b[N],c[N],e[N];int to[N],d[N],n,m,op,x,y;
multiset<ll>s[N],mn,mx;IT it;
void update(int x,ll vva,ll val,int ty){
if(!s[x].empty()){
it=mn.lower_bound((*s[x].begin())+e[x]),mn.erase(it);
it=mx.lower_bound((*--s[x].end())+e[x]),mx.erase(it);
}
// printf("%d\n",m);
if(ty==-1)it=s[x].lower_bound(vva),s[x].erase(it);
it=mn.lower_bound((*s[to[x]].begin())+e[to[x]]),mn.erase(it);
it=mx.lower_bound((*--s[to[x]].end())+e[to[x]]),mx.erase(it);
it=mn.lower_bound((*s[to[to[x]]].begin())+e[to[to[x]]]),mn.erase(it);
it=mx.lower_bound((*--s[to[to[x]]].end())+e[to[to[x]]]),mx.erase(it); it=s[to[x]].lower_bound(c[x]),s[to[x]].erase(it);
it=s[to[to[x]]].lower_bound(c[to[x]]),s[to[to[x]]].erase(it); c[to[x]]-=e[x],c[x]-=b[x]-d[x]*e[x]+e[x],d[x]+=ty;
e[x]=b[x]/d[x],c[x]+=b[x]-d[x]*e[x]+e[x],c[x]+=ty*val,c[to[x]]+=e[x]; if(ty==1)s[x].insert(vva);
s[to[x]].insert(c[x]),s[to[to[x]]].insert(c[to[x]]);
mn.insert((*s[to[x]].begin())+e[to[x]]);
mx.insert((*--s[to[x]].end())+e[to[x]]);
mn.insert((*s[to[to[x]]].begin())+e[to[to[x]]]);
mx.insert((*--s[to[to[x]]].end())+e[to[to[x]]]); if(!s[x].empty()){
mn.insert((*s[x].begin())+e[x]);
mx.insert((*--s[x].end())+e[x]);
}
}
int main(){
// freopen("testdata.in","r",stdin);
// freopen("testdata.out","w",stdout);
freopen("forest.in","r",stdin);
freopen("forest.out","w",stdout);
n=read(),m=read();
fp(i,1,n)b[i]=read(),++d[i];
fp(i,1,n)to[i]=read(),++d[i],++d[to[i]];
fp(i,1,n)e[i]=b[i]/d[i],c[i]=b[i]-d[i]*e[i]+e[i];
fp(i,1,n)c[to[i]]+=e[i];
fp(i,1,n)s[to[i]].insert(c[i]);
fp(i,1,n)if(!s[i].empty()){
mn.insert((*s[i].begin())+e[i]);
mx.insert((*--s[i].end())+e[i]);
}
while(m--){
op=read();
switch(op){
case 1:{
x=read(),y=read();if(to[x]==y)continue;
update(to[x],c[x],e[x],-1);
to[x]=y;
update(to[x],c[x],e[x],1);
break;
}
case 2:x=read(),print(c[x]+e[to[x]]);break;
case 3:print(*mn.begin()),sr[C]=' ',print(*--mx.end());break;
}
}return Ot(),0;
}

jzoj5989. 【北大2019冬令营模拟2019.1.6】Forest (set)的更多相关文章

  1. jzoj5990. 【北大2019冬令营模拟2019.1.6】Bear (状压dp)

    题面 题解 我永远讨厌dp.jpg 搞了一个下午优化复杂度最后发现只要有一个小trick就可以A了→_→.全场都插头dp就我一个状压跑得贼慢-- 不难发现我们可以状压,对于每一行,用状态\(S\)表示 ...

  2. jzoj5991. 【北大2019冬令营模拟2019.1.6】Juice

    题面 题解 好迷-- //minamoto #include<bits/stdc++.h> #define R register #define ll long long #define ...

  3. jzoj5984. 【北大2019冬令营模拟2019.1.1】仙人掌 (分块)

    题面 题解 数据结构做傻了.jpg 考虑每一个节点,它的儿子的取值最多只有\(O(\sqrt {m})\)种,那么可以用一个双向链表维护儿子的所有取值以及该取值的个数,那么对儿子节点修改一个值就是\( ...

  4. jzoj5983. 【北大2019冬令营模拟2019.1.1】多边形 (组合数学)

    这其实是道打表题--你看我代码就知道了-- 咳咳来点严谨证明好了-- 前方高能请注意 首先,正多边形近似于圆,可以看做在圆里内接多边形.圆内接多边形最多只有三个锐角.因为凸多边形的外角和为\(360\ ...

  5. JZOJ[5971]【北大2019冬令营模拟12.1】 party(1s,256MB)

    题目 题目大意 给你一棵树,在树上的某一些节点上面有人,要用最小的步数和,使得这些人靠在一起.所谓靠在一起,即是任意两个人之间的路径上没有空的节点(也就是连在一起). N≤200N \leq 200N ...

  6. [JZOJ5977] 【清华2019冬令营模拟12.15】堆

    题目 其中n,q≤500000n,q\leq 500000n,q≤500000 题目大意 让你维护一个堆.支持一下操作: 在某个点的下面加上另一个点,然后进行上浮操作. 询问某一点的权值. 思考历程 ...

  7. Visual Studio 2019 发布活动 - 2019 年 4 月 2 日

    Visual Studio 2019 发布活动 2019 年 4 月 2 日,星期二 | 上午 9:00 (PT) 围观: https://visualstudio.microsoft.com/zh- ...

  8. [2018冬令营模拟测试赛(二十一)]Problem A: Decalcomania

    [2018冬令营模拟测试赛(二十一)]Problem A: Decalcomania 试题描述 输入 见"试题描述" 输出 见"试题描述" 输入示例 见&quo ...

  9. jzoj6101. 【GDOI2019模拟2019.4.2】Path

    题目链接:https://jzoj.net/senior/#main/show/6101 记\(f_i\)为从\(i\)号点走到\(n\)号点所花天数的期望 那么根据\(m\)条边等可能的出现一条和一 ...

随机推荐

  1. [Cocoa]深入浅出Cocoa之Bonjour网络编程

    本文转载至 http://www.cnblogs.com/kesalin/archive/2011/09/15/cocoa_bonjour.html   深入浅出Cocoa之Bonjour网络编程 罗 ...

  2. 【BZOJ4476】[Jsoi2015]送礼物 分数规划+RMQ

    [BZOJ4476][Jsoi2015]送礼物 Description JYY和CX的结婚纪念日即将到来,JYY来到萌萌开的礼品店选购纪念礼物.萌萌的礼品店很神奇,所有出售的礼物都按照特定的顺序都排成 ...

  3. 开源G711(PCMA、PCMU)/G726转AAC项目EasyAACEncoder

    EasyDarwin开源社区整理了一份G711(PCMA.PCMU)/G726转AAC的转码库,支持Windows/Linux跨平台使用,将安防标准的G711转成移动互联网常用的AAC格式,希望能给大 ...

  4. Android 反编译工具

    想必玩安卓的童鞋大多都知道,安卓的APK安装包是可以反编译出源代码的,如果开发人员发布时没有对其混淆等加密处理,反编译出来的代码几乎与真实的源代码一模一样. 想要反编译apk,需要用到apktool. ...

  5. 判断DOM元素是否出现再浏览器窗口中

    几乎所有的项目都要解决这样一个问题:判断一个元素是否出现在浏览器窗口中?因为通过它我们可以极大的优化项目的性能,进而提升用户的的体验.原生javasxript获取浏览器的滚动距离和可视窗口的高度 使用 ...

  6. angularjs ng-repeat倒叙

    <div ng-app="myApp" ng-controller="customersCtrl"> <table> <tr ng ...

  7. 更改Windows的“视频”“图片”“”下载“文档”“音乐”“桌面”的默认路径

    右键-->属性

  8. UVA-11374(最短路)

    题意: 机场快线有经济线和商业线,现在分别给出经济线和商业线的的路线,现在只能坐一站商业线,其他坐经济线,问从起点到终点的最短用时是多少,还有路线是怎样的; 思路: 预处理出起点到所有站的最短距离和终 ...

  9. Opencv— — Color Gradient

    // define head function #ifndef PS_ALGORITHM_H_INCLUDED #define PS_ALGORITHM_H_INCLUDED #include < ...

  10. 移植最新版libmemcached到VC++的艰苦历程和经验总结(下)

    结果如何呢?我的VC++测试用例还是不能调用该接口的接口方法,只是这次的报错方式有所改变,提示是每个C/C++程序员最不愿意看到的“内存地址访问违规”,这一次我确实被郁闷了,这是为什么呢? 五.gcc ...