这题太神仙了必须写博客。。。

显然可以想到二分答案。二分一个答案mid,如果所有长度\(\geq mid\)的路径都过x,那么答案一定\(<mid\),否则答案\(\geq mid\)。

那么就可以写出代码了,树状数组套动态开点线段树即可。时间复杂度\(O(n(log_2n)^3)\)

然后因为出题人卡空间就炸了。。。如果256M就能过了。。

  1. #include<bits/stdc++.h>
  2. #define il inline
  3. #define vd void
  4. typedef long long ll;
  5. il int gi(){
  6. int x=0,f=1;
  7. char ch=getchar();
  8. while(!isdigit(ch)){
  9. if(ch=='-')f=-1;
  10. ch=getchar();
  11. }
  12. while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
  13. return x*f;
  14. }
  15. int n,m,fir[100010],nxt[200010],dis[200010],id;
  16. il vd link(int a,int b){
  17. nxt[++id]=fir[a],fir[a]=id,dis[id]=b;
  18. nxt[++id]=fir[b],fir[b]=id,dis[id]=a;
  19. }
  20. int dfn[100010],dep[100010],fa[100010],siz[100010],son[100010];
  21. il vd dfs(int x){
  22. siz[x]=1;
  23. for(int i=fir[x];i;i=nxt[i]){
  24. if(dep[dis[i]])continue;
  25. dep[dis[i]]=dep[x]+1;
  26. fa[dis[i]]=x;
  27. dfs(dis[i]);
  28. siz[x]+=siz[dis[i]];
  29. if(siz[son[x]]<=siz[dis[i]])son[x]=dis[i];
  30. }
  31. }
  32. int top[100010];
  33. il vd dfs2(int x,int tp){
  34. top[x]=tp;dfn[x]=++dfn[0];
  35. if(son[x])dfs2(son[x],tp);
  36. for(int i=fir[x];i;i=nxt[i])if(fa[x]!=dis[i]&&son[x]!=dis[i])dfs2(dis[i],dis[i]);
  37. }
  38. int o[200010],u[200010],v[200010],w[200010];
  39. int uni_w[200010],uni_w_tot;
  40. int cnt,rt[200010],ls[15000001],rs[15000001],lz[15000001];
  41. #define mid ((l+r)>>1)
  42. il vd _update(int&x,int l,int r,const int&L,const int&R,const int&d){
  43. if(!x)x=++cnt;
  44. if(L<=l&&r<=R){lz[x]+=d;return;}
  45. if(L<=mid)_update(ls[x],l,mid,L,R,d);
  46. if(mid<R)_update(rs[x],mid+1,r,L,R,d);
  47. }
  48. il int _query(int&x,int l,int r,const int&p){
  49. if(!x)return 0;
  50. if(l==r)return lz[x];
  51. if(p<=mid)return lz[x]+_query(ls[x],l,mid,p);
  52. else return lz[x]+_query(rs[x],mid+1,r,p);
  53. }
  54. #undef mid
  55. il vd Update(const int&p,const int&l,const int&r,const int&d){
  56. int x=p;
  57. while(x<=uni_w_tot)_update(rt[x],1,n,l,r,d),x+=x&-x;
  58. }
  59. il int Query(const int&p,const int&l){
  60. int x=p,ret=0;
  61. while(x)ret+=_query(rt[x],1,n,l),x-=x&-x;
  62. return ret;
  63. }
  64. int t[200010];
  65. il vd bit_update(int x,int d){while(x<=uni_w_tot)t[x]+=d,x+=x&-x;}
  66. il int bit_query(int x){int r=0;while(x)r+=t[x],x-=x&-x;return r;}
  67. int main(){
  68. n=gi(),m=gi();
  69. for(int i=1;i<n;++i)link(gi(),gi());
  70. int RT=rand()%n+1;
  71. dep[RT]=1,dfs(RT),dfs2(RT,RT);
  72. for(int i=1;i<=m;++i){
  73. o[i]=gi();
  74. if(o[i]==0)u[i]=gi(),v[i]=gi(),w[i]=gi(),uni_w[++uni_w_tot]=-w[i];
  75. else if(o[i]==1){
  76. int t=gi();
  77. u[i]=u[t],v[i]=v[t],w[i]=w[t];
  78. }else if(o[i]==2)u[i]=gi();
  79. }
  80. std::sort(uni_w+1,uni_w+uni_w_tot+1);uni_w_tot=std::unique(uni_w+1,uni_w+uni_w_tot+1)-uni_w-1;
  81. for(int i=1;i<=m;++i)if(o[i]!=2)w[i]=std::lower_bound(uni_w+1,uni_w+uni_w_tot+1,-w[i])-uni_w;
  82. for(int i=1;i<=uni_w_tot;++i)uni_w[i]=-uni_w[i];
  83. for(int i=1;i<=m;++i){
  84. if(o[i]^2){
  85. int x=u[i],y=v[i],d=o[i]==0?1:-1;
  86. while(top[x]!=top[y])
  87. if(dep[top[x]]>dep[top[y]])Update(w[i],dfn[top[x]],dfn[x],d),x=fa[top[x]];
  88. else Update(w[i],dfn[top[y]],dfn[y],d),y=fa[top[y]];
  89. if(dfn[x]>dfn[y])std::swap(x,y);
  90. Update(w[i],dfn[x],dfn[y],d);
  91. bit_update(w[i],d);
  92. }else{
  93. if(!bit_query(uni_w_tot)){puts("-1");continue;}
  94. int l=1,r=uni_w_tot+1,mid;
  95. while(l<r){
  96. mid=((l+r)>>1);
  97. if(Query(mid,dfn[u[i]])==bit_query(mid))l=mid+1;
  98. else r=mid;
  99. }
  100. if(l<=uni_w_tot)printf("%d\n",uni_w[l]);
  101. else puts("-1");
  102. }
  103. }
  104. return 0;
  105. }

然后学了一发神仙整体二分

大概就是说答案要用二分求,可以放在一起二分

大概就是void solve(int l,int r,int L,int R),就是\([L,R]\)的操作/询问,操作的权值都\(\in[l,r]\),这里面的查询都已经确定了在\([l,r]\)范围内。

如果\(l=r\)直接更新答案就好了,否则要确定这里面所有查询的

按时间顺序操作,如果当前是修改而且权值\(\geq mid\),就加入/删除一条u-v的路径;如果是询问就所有的路径是否都经过当前点即可,就能知道这个询问的答案是否\(\geq mid\)。具体实现可以简单树上差分。

然后递归调用下去。

然后代码为了卡常把\(\geq\)改成了\(\leq\),具体见代码。。

  1. #include<bits/stdc++.h>
  2. #define il inline
  3. #define vd void
  4. typedef long long ll;
  5. il int gi(){
  6. int x=0;
  7. char ch=getchar();
  8. while(!isdigit(ch))ch=getchar();
  9. while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
  10. return x;
  11. }
  12. int n,m,fir[100010],nxt[200010],dis[200010],id;
  13. il vd link(int a,int b){
  14. nxt[++id]=fir[a],fir[a]=id,dis[id]=b;
  15. nxt[++id]=fir[b],fir[b]=id,dis[id]=a;
  16. }
  17. int dfn[100010],dep[100010],fa[100010],siz[100010],son[100010];
  18. il vd dfs(int x){
  19. siz[x]=1;
  20. for(int i=fir[x];i;i=nxt[i]){
  21. if(dep[dis[i]])continue;
  22. dep[dis[i]]=dep[x]+1;
  23. fa[dis[i]]=x;
  24. dfs(dis[i]);
  25. siz[x]+=siz[dis[i]];
  26. if(siz[son[x]]<=siz[dis[i]])son[x]=dis[i];
  27. }
  28. }
  29. int top[100010];
  30. il vd dfs2(int x,int tp){
  31. top[x]=tp;dfn[x]=++dfn[0];
  32. if(son[x])dfs2(son[x],tp);
  33. for(int i=fir[x];i;i=nxt[i])if(fa[x]!=dis[i]&&son[x]!=dis[i])dfs2(dis[i],dis[i]);
  34. }
  35. struct ques{int o,u,v,w,i,lca;bool y;}s[200010],a[200010],b[200010];
  36. int uni_w[200010],uni_w_tot,ans[200010];
  37. int t[200010];
  38. il vd update(int x,int d){while(x<=n)t[x]+=d,x+=x&-x;}
  39. il int query(int x){int r=0;while(x)r+=t[x],x-=x&-x;return r;}
  40. il vd solve(int l,int r,int L,int R){
  41. if(L>R)return;
  42. for(int i=L;i<=R;++i)if(s[i].o==2)goto GG;
  43. return;GG:;
  44. if(l==r){for(int i=L;i<=R;++i)if(s[i].i)ans[s[i].i]=l;return;}
  45. int mid=(l+r)>>1,tot=0,A=0,B=0;
  46. for(int i=L;i<=R;++i)
  47. if(s[i].o==2){
  48. if(query(dfn[s[i].u]+siz[s[i].u]-1)-query(dfn[s[i].u]-1)==tot)b[++B]=s[i];
  49. else a[++A]=s[i];
  50. }else if(s[i].w<=mid){
  51. int d=s[i].o?-1:1;
  52. tot+=d;
  53. update(dfn[s[i].u],d);update(dfn[s[i].v],d);
  54. update(dfn[s[i].lca],-d);if(s[i].lca!=1)update(dfn[fa[s[i].lca]],-d);
  55. a[++A]=s[i];
  56. }else b[++B]=s[i];
  57. memcpy(s+L,a+1,(sizeof(ques))*A);
  58. memcpy(s+L+A,b+1,(sizeof(ques))*B);
  59. for(int i=L;i<=R;++i)
  60. if(s[i].o!=2&&s[i].w<=mid&&s[i].y){
  61. int d=s[i].o?1:-1;
  62. update(dfn[s[i].u],d);update(dfn[s[i].v],d);
  63. update(dfn[s[i].lca],-d);if(s[i].lca!=1)update(dfn[fa[s[i].lca]],-d);
  64. }
  65. solve(l,mid,L,L+A-1),solve(mid+1,r,L+A,R);
  66. }
  67. int main(){
  68. n=gi(),m=gi();
  69. for(int i=1;i<n;++i)link(gi(),gi());
  70. dep[1]=1,dfs(1),dfs2(1,1);
  71. for(int i=1;i<=m;++i){
  72. s[i].o=gi();
  73. if(s[i].o==0){
  74. s[i].u=gi(),s[i].v=gi(),s[i].w=gi(),uni_w[++uni_w_tot]=-s[i].w;s[i].y=1;
  75. int x=s[i].u,y=s[i].v;
  76. while(top[x]!=top[y]){
  77. if(dep[top[x]]>dep[top[y]])x=fa[top[x]];
  78. else y=fa[top[y]];
  79. }
  80. s[i].lca=(dep[x]<dep[y])?x:y;
  81. }else if(s[i].o==1){
  82. int x=gi();
  83. s[i]=s[x],s[i].o=1;
  84. s[i].y=s[x].y=0;
  85. }else s[i].u=gi(),s[i].i=++ans[0];
  86. }
  87. uni_w[++uni_w_tot]=1;
  88. std::sort(uni_w+1,uni_w+uni_w_tot+1);uni_w_tot=std::unique(uni_w+1,uni_w+uni_w_tot+1)-uni_w-1;
  89. for(int i=1;i<=m;++i)if(s[i].o!=2)s[i].w=std::lower_bound(uni_w+1,uni_w+uni_w_tot+1,-s[i].w)-uni_w;
  90. for(int i=1;i<=uni_w_tot;++i)uni_w[i]=-uni_w[i];
  91. solve(1,uni_w_tot,1,m);
  92. for(int i=1;i<=ans[0];++i)printf("%d\n",uni_w[ans[i]]);
  93. return 0;
  94. }

卡了一波常数就洛咕rk1,bzoj rk7了。。

upd:又改了一波 bzojrk1了

洛咕P3250 [HNOI2016]网络 整体二分的更多相关文章

  1. 洛谷P3250 [HNOI2016]网络(整体二分+树状数组+树剖)

    传送门 据说正解是树剖套堆???然而代码看着稍微有那么一点点长…… 考虑一下整体二分,设当前二分到的答案为$mid$,如果所有大于$mid$的边都经过当前点$x$,那么此时$x$的答案必定小于等于$m ...

  2. BZOJ 4538: [Hnoi2016]网络 [整体二分]

    4538: [Hnoi2016]网络 题意:一棵树,支持添加一条u到v权值为k的路径,删除之前的一条路径,询问不经过点x的路径的最大权值 考虑二分 整体二分最大权值,如果\(k \in [mid+1, ...

  3. 【BZOJ4538】[Hnoi2016]网络 整体二分+树状数组

    [BZOJ4538][Hnoi2016]网络 Description 一个简单的网络系统可以被描述成一棵无根树.每个节点为一个服务器.连接服务器与服务器的数据线则看做一条树边.两个服务器进行数据的交互 ...

  4. [洛谷P3250][HNOI2016]网络

    题目大意:给定一棵树.有三种操作: $0\;u\;v\;t:$在$u$到$v$的链上进行重要度为$t$的数据传输. $1\;x:$结束第$x$个数据传输. $2\;x:$询问不经过点$x$的数据传输中 ...

  5. P3250 [HNOI2016] 网络 (树剖+堆/整体二分+树上差分+树状数组)

    解法1: 本题有插入路径和删除路径,在每个节点维护插入堆和删除堆,查询时两者top一样则一直弹出.如果每个节点维护的是经过他的路径,显然有些不好处理,正难则反,每个点维护不经过他的路径,那么x节点出了 ...

  6. luogu P3250 [HNOI2016]网络

    传送门 考虑只有一个询问,怎么使用暴力枚举最快的得到答案.因为要求最大的,所以可以把链按权值从大往小排序,然后往后扫,找到一个没有交的就是答案,直接退出 一堆询问,可以考虑整体二分,先二分一个值\(m ...

  7. P3250 [HNOI2016]网络

    LINK:网络 一棵树 每次添加一条路径 或者删除之前的一条路径 或询问除了不经过某个点之外剩下的最大值. 一个显然的思路 对于一条路径的权值我们直接把权值塞上去 标记永久化一下即可. 考虑如何求答案 ...

  8. luogu3250 网络 (整体二分+树上差分+树状数组)

    首先整体二分,问题变成是否存在经过一个点的满足条件的路径 那么我对于每个路径(a,b,lca),在树状数组的dfn[a]++,dfn[b]++,dfn[lca]--,dfn[fa[lca]--] 然后 ...

  9. 洛谷P3527 MET-Meteors [POI2011] 整体二分

    正解:整体二分 解题报告: 传送门! 还有个双倍经验!(明明是一样的题目为什么你们一个紫一个黑啊喂! 这题首先要想到可以二分嘛,然后看到多组询问肯定就整体二分鸭 那就是基本套路啊,发现是区间修改单点查 ...

随机推荐

  1. RHEL7: How to configure a rc-local service

    问题: linux7 /etc/rc.local 不生效: [root@bogon mysql3306]# uname -aLinux bogon 3.10.0-862.el7.x86_64 #1 S ...

  2. [翻译] EAIntroView

    EAIntroView https://github.com/ealeksandrov/EAIntroView   This is highly customizable drop-in soluti ...

  3. Windows与Linux 互相访问,挂载过程

    开始使用Linux时浏览器无法访问,多次尝试以失败告终,果断放弃自我动手, 找了大神帮助,弄了半天终于可以访问.但是之前在Windows下的文件也不能放弃,从大神那里那里文档,然后进行尝试 1.在Wi ...

  4. [原创]获取JS数组最大值、最小值

    核心关键 JS有Array数组对象,使用prototype内置属性扩展,增加Array数组max().min()方法 具体代码 //最小值 Array.prototype.min = function ...

  5. linux中ftp提示--553 Could not create file

    今天在阿里云的linux上搭建ftp服务的时候,搭建成功之后,上传文件时总提示553 Could not create file,找了半天原因,终于解决了 ftp主目录为/home/myftp /ho ...

  6. 作业一 制作PC配置 吴昊

  7. php实现session入库

    为什么要把session存入数据库?有什么用? 可以:统计在线人数,现实多站点session共享(通行证),控制同个账号登入人数等. 要实现session的入库,有关键的几个基本知识: session ...

  8. mysql创建表的注意事项

    1 库名,表名,字段名必须使用小写字母,"_"分割. 2 库名,表名,字段名必须不超过12个字符. 3 库名,表名,字段名见名识意,建议使用名词而不是动词. 4 建议使用InnoD ...

  9. 开源作业调度框架 - Quartz.NET - 实战使用1

    简介: 第一步:下载Quartz.NET 下载Quartz.NET只需要打开网址选择适宜的版本进行下载解压缩即可. 目前最新版本是2.3.3,压缩包为6MB,不过鉴于国内网速.我还是加一下博客园的下载 ...

  10. UI(二)之正式过程

    2018-12-04 09:48:25 1.SetWindowsHookEx ·钩子实际上是一个处理消息的程序段,通过系统调用,把它挂入系统.每当特定的消息发出,在没有到达目的窗口前,钩子程序就先捕获 ...