传送门

Descroption

带修改求树上路径第k大

Solution

方法一:树状数组套主席树

出题人总是比较喜欢把序列的东西搬到树上去

但这并不影响我们做题,因为我们可以用一个log的时间将它变回序列的操作(树链剖分)

使用树状数组,是因为它可以支持单点加和区间求和的操作。

我们求出dfs序,然后按照顺序,将每个点离散后的权值,加到树状数组上去

其实是加到树状数组每个点所对应的权值线段树上

这样,我们处理操作的时候:

  • 修改操作:就和之前的加点一样,在原权值处-1,新权值处+1
  • 询问操作:找出x和y到它们的lca上的log条重链,每条链都对应dfs序的一个区间,我们先记录下这log个区间,然后在权值线段树上二分,对这些区间的端点加加减减一下,就能求出相应权值区间的数量啦

复杂度是\(O(n \log^3 n)\)的

之前求成第k小了,wa了无数次,我真菜

Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
inline int read()
{int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}return x*f;
}
#define reg register
#define MN 80005
int n,m,val[MN],s[MN<<1],tot;
struct OPT{int l,r,k;}o[MN];
int ls[MN*200],rs[MN*200],t[MN*200],sz,rt[MN];
#define mid ((l+r)>>1)
void Modify(int &rt,int l,int r,int x,int v)
{++sz;ls[sz]=ls[rt];rs[sz]=rs[rt];t[sz]=t[rt]+v;rt=sz;if(l==r) return;if(x<=mid) Modify(ls[rt],l,mid,x,v);else Modify(rs[rt],mid+1,r,x,v);
}
int tmp[400],cnt,sign[400];
int Query(int l,int r,int k)
{if(l==r) return l;register int sum=0,i;for(i=1;i<=cnt;++i) sum+=t[rs[tmp[i]]]*sign[i];if(k<=sum){for(i=1;i<=cnt;++i) tmp[i]=rs[tmp[i]];return Query(mid+1,r,k);}else{for(i=1;i<=cnt;++i) tmp[i]=ls[tmp[i]];return Query(l,mid,k-sum);}
}
#define lb(x) (x&(-x))
inline void C(int x,int p,int v){for(;x<=n;x+=lb(x)) Modify(rt[x],1,tot,p,v);}
struct edge{int to,nex;}e[MN<<1];int hr[MN],en;
inline void ins(int f,int t)
{e[++en]=(edge){t,hr[f]};hr[f]=en;e[++en]=(edge){f,hr[t]};hr[t]=en;
}
int dfn[MN],fdfn[MN],mx[MN],top[MN],siz[MN],fa[MN],dep[MN],dind;
void dfs1(int x,int f)
{dep[x]=dep[fa[x]=f]+1;siz[x]=1;for(reg int i=hr[x];i;i=e[i].nex) if(f^e[i].to)dfs1(e[i].to,x),siz[e[i].to]>siz[mx[x]]?mx[x]=e[i].to:0,siz[x]+=siz[e[i].to];
}
void dfs2(int x,int tp)
{dfn[x]=++dind;fdfn[dind]=x;top[x]=tp;if(mx[x]) dfs2(mx[x],tp);for(reg int i=hr[x];i;i=e[i].nex) if((fa[x]^e[i].to)&&(mx[x]^e[i].to))dfs2(e[i].to,e[i].to);
}
inline void Insert(int l,int r)
{for(;r;r-=lb(r)) tmp[++cnt]=rt[r],sign[cnt]=1;for(--l;l;l-=lb(l)) tmp[++cnt]=rt[l],sign[cnt]=-1;
}
inline void que(int x,int y,int k)
{cnt=0;int num=1+dep[x]+dep[y];while(top[x]^top[y]){if(dep[top[x]]>dep[top[y]]) Insert(dfn[top[x]],dfn[x]),x=fa[top[x]];else Insert(dfn[top[y]],dfn[y]),y=fa[top[y]];}if(dep[x]<dep[y]) std::swap(x,y);Insert(dfn[y],dfn[x]);num-=2*dep[y];if(num<k) puts("invalid request!");else printf("%d\n",s[Query(1,tot,k)]);
}
int main()
{n=read();m=read();register int i,x;for(i=1;i<=n;++i) ++tot,s[tot]=val[i]=read();for(i=1;i<n;++i) x=read(),ins(x,read());for(i=1;i<=m;++i){o[i].k=read();o[i].l=read(),o[i].r=read();if(!o[i].k) ++tot,s[tot]=o[i].r;}std::sort(s+1,s+tot+1);tot=std::unique(s+1,s+tot+1)-s-1;for(i=1;i<=n;++i) val[i]=std::lower_bound(s+1,s+tot+1,val[i])-s;for(i=1;i<=m;++i) if(!o[i].k) o[i].r=std::lower_bound(s+1,s+tot+1,o[i].r)-s;dfs1(1,0);dfs2(1,1);for(i=1;i<=n;++i) C(i,val[fdfn[i]],1);for(i=1;i<=m;++i){if(!o[i].k) C(dfn[o[i].l],val[o[i].l],-1),C(dfn[o[i].l],o[i].r,1),val[o[i].l]=o[i].r;else que(o[i].l,o[i].r,o[i].k);}return 0;
}

方法二:整体二分

仍然是树链剖分

用上整体二分的套路

修改操作可以看成一次加点和一次删点

upd:大概在一周后,终于补上了整体二分的代码......

复杂度仍然是\(O(n \log^3 n)\)的

我怎么再次打成了第k小,我是有智力问题吧(疯了)......

Code

#include<bits/stdc++.h>
#define ll long long
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
inline int read()
{int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}return x*f;
}
#define MN 30002
#define MM 80002
int n,tot,ID,val[MM],Ans[MN];
int num[MN+MM],cnt;
struct opt{int x,y,k,id;}q[MM+(MN<<1)],p[MM+(MN<<1)];
struct edge{int to,nex;}e[MM<<1];int hr[MM],en;
inline void ins(int f,int t)
{e[++en]=(edge){t,hr[f]};hr[f]=en;e[++en]=(edge){f,hr[t]};hr[t]=en;
}
int dep[MM],fa[MM],top[MM],mx[MM],sz[MM],dfn[MM],dind;
inline void dfs1(int x=1,int f=0)
{dep[x]=dep[fa[x]=f]+(sz[x]=1);register int i;for(i=hr[x];i;i=e[i].nex)if(e[i].to^f) dfs1(e[i].to,x),(sz[e[i].to]>sz[mx[x]])?mx[x]=e[i].to:0,sz[x]+=sz[e[i].to];
}
inline void dfs2(int x=1,int tp=1)
{dfn[x]=++dind;top[x]=tp;if(mx[x]) dfs2(mx[x],tp);register int i;for(i=hr[x];i;i=e[i].nex)if((e[i].to^fa[x])&&(e[i].to^mx[x])) dfs2(e[i].to,e[i].to);
}
#define lb(x) (x&(-x))
int t[MM];
inline void C(int x,int v){for(;x<=n;x+=lb(x))t[x]+=v;}
inline int G(int x){int r=0;for(;x;x-=lb(x))r+=t[x];return r;}
inline int get_lca(int x,int y){for(;top[x]^top[y];)if(dep[top[x]]>dep[top[y]])x=fa[top[x]];else y=fa[top[y]];return dep[x]>dep[y]?y:x;
}
inline int get_num(int x,int y)
{int r=0;for(;top[x]^top[y];)dep[top[x]]>dep[top[y]]?(r+=G(dfn[x])-G(dfn[top[x]]-1),x=fa[top[x]]):(r+=G(dfn[y])-G(dfn[top[y]]-1),y=fa[top[y]]);r+=G(max(dfn[x],dfn[y]))-G(min(dfn[x],dfn[y])-1);return r;
}
void solve(int l=1,int r=cnt,int ql=1,int qr=tot)
{if(ql>qr) return;register int i;if(l==r){for(i=ql;i<=qr;++i) if(q[i].id) Ans[q[i].id]=num[l];return;}register int mid=(l+r+1)>>1,pl=ql,pr=qr,tmp;for(i=ql;i<=qr;++i){if(!q[i].id){if(q[i].y>=num[mid]) p[pr--]=q[i],C(dfn[q[i].x],q[i].k);else p[pl++]=q[i];}else{tmp=get_num(q[i].x,q[i].y);if(tmp>=q[i].k) p[pr--]=q[i];else q[i].k-=tmp,p[pl++]=q[i];}}for(i=ql;i<=qr;++i) if(!q[i].id&&q[i].y>=num[mid]) C(dfn[q[i].x],-q[i].k);for(i=ql;i<pl;++i) q[i]=p[i];for(i=pl;i<=qr;++i) q[i]=p[qr-i+pl];solve(l,mid-1,ql,pl-1);solve(mid,r,pr+1,qr);
}
int main()
{register int i,m,x,k,y;n=read();m=read();for(i=1;i<=n;++i) q[++tot]=(opt){i,val[i]=read(),1,0},num[++cnt]=val[i];for(i=1;i<n;++i) x=read(),ins(x,read());dfs1();dfs2();while(m--){k=read();x=read();y=read();if(!k) q[++tot]=(opt){x,val[x],-1,0},q[++tot]=(opt){x,y,1,0},num[++cnt]=val[x]=y;else{++ID;register int lca=get_lca(x,y);if(dep[x]+dep[y]-2*dep[lca]+1<k) Ans[ID]=-1;else q[++tot]=(opt){x,y,k,ID};}}std::sort(num+1,num+cnt+1);cnt=std::unique(num+1,num+cnt+1)-num-1;solve();for(i=1;i<=ID;++i) printf(Ans[i]==-1?"invalid request!\n":"%d\n",Ans[i]);return 0;
}

Blog来自PaperCloud,未经允许,请勿转载,TKS!

转载于:https://www.cnblogs.com/PaperCloud/p/10152249.html

[CTSC2008]网络管理Network相关推荐

  1. BZOJ 1146: [CTSC2008]网络管理Network( 树链剖分 + 树状数组套主席树 )

    树链剖分完就成了一道主席树裸题了, 每次树链剖分找出相应区间然后用BIT+(可持久化)权值线段树就可以完成计数. 但是空间问题很严重....在修改时不必要的就不要新建, 直接修改原来的..详见代码. ...

  2. 【bzoj1146】 [CTSC2008]网络管理Network【树链剖分+树套树+二分 线段树套Treap】

    1146: [CTSC2008]网络管理Network Description M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个 部门之间协同工作,公 ...

  3. bzoj 1146 [CTSC2008]网络管理Network

    很久之前写过 count on the tree. 然后一直不懂树状数组是怎么套上这个主席树的. 看了两小时发现它套的就是个权值线段树, 看不出来可持久化在哪里. 因为动态开点所以空间nlog2n. ...

  4. BZOJ1146 [CTSC2008]网络管理Network 树链剖分 主席树 树状数组

    欢迎访问~原文出处--博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1146 题意概括 在一棵树上,每一个点一个权值. 有两种操作: 1.单点修改 2.询问两点之间的树链 ...

  5. P4175 [CTSC2008]网络管理(整体二分)

    P4175 [CTSC2008]网络管理 给定一棵有nnn个节点的树,点有点权,有两种操作:① 修改某个点的点权,② 查询两点路径间的点权第kkk大. 给定u,vu, vu,v,选定111号节点为根节 ...

  6. P4175 [CTSC2008]网络管理 (动态树上第k大)

    题目链接: P4175 [CTSC2008]网络管理 大致题意 给定一棵有nnn个节点的树, 节点上有权值wiw_iwi​. 有mmm次操作. 0 a b 表示把节点aaa的权值修改为bbb. 即: ...

  7. CODEVS1490 [CTSC2008]网络管理

    题目描述 Description M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个部门之间 协同工作,公司搭建了一个连接整个公司的通信网络.该网络的结 ...

  8. 洛谷 P4175: bzoj 1146: [CTSC2008]网络管理

    令人抓狂的整体二分题.根本原因还是我太菜了. 在学校写了一个下午写得头晕,回家里重写了一遍,一个小时就写完了--不过还是太慢. 题目传送门:洛谷P4175. 题意简述: 一棵 \(n\) 个结点的树, ...

  9. BZOJ1146[CTSC2008]网络管理——出栈入栈序+树状数组套主席树

    题目描述 M公司是一个非常庞大的跨国公司,在许多国家都设有它的下属分支机构或部门.为了让分布在世界各地的N个 部门之间协同工作,公司搭建了一个连接整个公司的通信网络.该网络的结构由N个路由器和N-1条 ...

最新文章

  1. Oracle 10g RAC OCR 和 VotingDisk 的备份与恢复
  2. android本地socket正常,【报Bug】Android 本地打包 websocket 出错
  3. Spring自学日志02(对象的创建,依赖注入)
  4. Kafka MirrorMaker2.0 (异地双活/跨数据中心容灾/跨集群容灾)
  5. win10 安装visual studio 2015遇到的坑
  6. STM32的ADC精度提高方法
  7. 虚拟服务器数据库怎么导入数据库,BlueHost虚拟主机使用SSH怎么导入MySQL数据库...
  8. java 修改mysql密码_mysql数据库忘记密码时如何修改
  9. python计算工资_python学习之工资结算
  10. 银行对公业务和对私业务
  11. 亲身经历:程序人生路上的荆棘与感动
  12. 素描小子跑酷html5游戏在线玩,体验Html5实现的在线素描及绘画设计
  13. Go语言(Golang)的Web框架比较:gin VS echo
  14. druid字段级_Druid配置
  15. P8-Windows与网络基础-Windows基本命令-目录文件操作(cd、dir、md、rd、move、copy、xcopy、del)
  16. NB-IoT门磁报警器 物联网门磁传感器 电子封条报警器
  17. TCP/IP 网络协议基础入门
  18. echarts 江苏省地图各市级坐标点
  19. 图像风格迁移做了一件文化衫-【布尔艺数】
  20. C Primer Plus 第六版 章节课后编程练习答案(下)(缘更)

热门文章

  1. 天地图怎么看历史图像_解密:看猪八戒是怎么由一头猪变成天蓬元帅的
  2. (1)剑指Offer之斐波那契数列问题和跳台阶问题
  3. 大量删除的表、查询卡顿的表,重建索引
  4. poi实现excel数据导入数据库
  5. Codeigniter基础
  6. 重写Android系统自带Dialog
  7. php导出服务器表格乱码,phpExcel导出, 在本地正常,在服务器乱码解决办法
  8. echarts 柱状图颜色_echarts的实战案例一些(二)
  9. c++ char*初始化_[零食时间]C/C++ 字符串全家桶(字符串表示/定义、字符串输入输出、易错点等)上半桶...
  10. 什么是JDK,什么是JRE?JDK的安装和环境变量的配置