bzoj4009: [HNOI2015]接水果(整体二分)
题目描述
风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果。由于她已经DT FC 了The big black, 她觉得这个游戏太简单了,于是发明了一个更加难的版本。
首先有一个地图,是一棵由 n 个顶点、n-1 条边组成的树(例如图 1给出的树包含 8 个顶点、7 条边)。
这颗树上有 P 个盘子,每个盘子实际上是一条路径(例如图 1 中顶点 6 到顶点 8 的路径),并且每个盘子还有一个权值。第 i 个盘子就是顶点a_i到顶点b_i的路径(由于是树,所以从a_i到b_i的路径是唯一的),权值为c_i。
接下来依次会有Q个水果掉下来,每个水果本质上也是一条路径,第i 个水果是从顶点 u_i 到顶点v_i 的路径。
幽香每次需要选择一个盘子去接当前的水果:一个盘子能接住一个水果,当且仅当盘子的路径是水果的路径的子路径(例如图1中从 3到7 的路径是从1到8的路径的子路径)。这里规定:从a 到b的路径与从b到 a的路径是同一条路径。
当然为了提高难度,对于第 i 个水果,你需要选择能接住它的所有盘子中,权值第 k_i 小的那个盘子,每个盘子可重复使用(没有使用次数的上限:一个盘子接完一个水果后,后面还可继续接其他水果,只要它是水果路径的子路径)。幽香认为这个游戏很难,你能轻松解决给她看吗? < width="395" height="212" alt="" />
输入输出格式
输入格式:
第一行三个数 n和P 和Q,表示树的大小和盘子的个数和水果的个数。 接下来n-1 行,每行两个数 a、b,表示树上的a和b 之间有一条边。树中顶点按1到 n标号。 接下来 P 行,每行三个数 a、b、c,表示路径为 a 到 b、权值为 c 的盘子,其中0<=c<=10^9,a不等于b。 接下来Q行,每行三个数 u、v、k,表示路径为 u到 v的水果,其中 u不等于v,你需要选择第 k小的盘子,第k 小一定存在。
输出格式:
对于每个果子,输出一行表示选择的盘子的权值。
输入输出样例
10 10 10 1 2 2 3 3 4 4 5 5 6 6 7 7 8 8 9 9 10 3 2 217394434 10 7 13022269 6 7 283254485 6 8 333042360 4 6 442139372 8 3 225045590 10 4 922205209 10 8 808296330 9 2 486331361 4 9 551176338 1 8 5 3 8 3 3 8 4 1 8 3 4 8 1 2 3 1 2 3 1 2 3 1 2 4 1 1 4 1
442139372 333042360 442139372 283254485 283254485 217394434 217394434 217394434 217394434 217394434
说明
N,P,Q<=40000。
题解
收获良多……知道了整体二分是个啥……知道了不用CDQ直接求矩形覆盖……balabala(我很好奇自己是怎么看懂题解的)
先考虑一下怎么判断一条路径是否被另一条路劲覆盖
我们记录一下每一个点的dfs序,其中$ls_u=dfn_u,rs_u=dfn_u+size_u-1$,这个应该是基本操作
然后我们考虑一下
我们把路径表示为二维平面上的一个点,$(ls_u,ls_v)(ls_u<ls_v)$,设询问为$x->y$且$ls_x<ls_y$
如果$lca(u,v)!=u$,那么必定满足$x$在$u$的子树里,$y$在$v$的子树内,也就满足$ls_u\leq ls_x \leq rs_u,ls_v\leq ls_y \leq rs_v$,那么就是点$(ls_x,ls_y)$在矩形${(ls_u,ls_v),(rs_u,rs_v)}$里面
如果$lca(u,v)==u$,那么设$z$为$u->v$路径上的第一个点,那么必定有一个点在$v$子树内,另一个点在$v$子树外,就是点$(ls_x,ls_y)$在矩形${(1,ls_v),(ls_z-1,rs_v)}\bigcup {(ls_v,rs_z+1),(rs_v,n)}$里面
那么我们可以整体二分,二分一个答案,然后统计每一个点被矩形覆盖了多少次,然后不断这样做下去就行了
至于怎么快速求一个点被矩形覆盖多少次,可以先排序去掉$x$的影响,然后用树状数组存储前缀和并查询
1 //minamoto 2 #include<iostream> 3 #include<cstdio> 4 #include<algorithm> 5 using namespace std; 6 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 7 char buf[1<<21],*p1=buf,*p2=buf; 8 inline int read(){ 9 #define num ch-'0' 10 char ch;bool flag=0;int res; 11 while(!isdigit(ch=getc())) 12 (ch=='-')&&(flag=true); 13 for(res=num;isdigit(ch=getc());res=res*10+num); 14 (flag)&&(res=-res); 15 #undef num 16 return res; 17 } 18 char sr[1<<21],z[20];int C=-1,Z; 19 inline void Ot(){fwrite(sr,1,C+1,stdout),C=-1;} 20 inline void print(int x){ 21 if(C>1<<20)Ot();if(x<0)sr[++C]=45,x=-x; 22 while(z[++Z]=x%10+48,x/=10); 23 while(sr[++C]=z[Z],--Z);sr[++C]='\n'; 24 } 25 const int N=40005; 26 int ver[N<<1],Next[N<<1],head[N],tot=0; 27 int val[N],fa[N],dep[N],son[N],sz[N],ls[N],rs[N],top[N]; 28 int n,p,q,cnt,num; 29 inline void add(int u,int v){ 30 ver[++tot]=v,Next[tot]=head[u],head[u]=tot; 31 ver[++tot]=u,Next[tot]=head[v],head[v]=tot; 32 } 33 void dfs1(int u){ 34 sz[u]=1,dep[u]=dep[fa[u]]+1; 35 for(int i=head[u];i;i=Next[i]){ 36 int v=ver[i]; 37 if(v!=fa[u]){ 38 fa[v]=u,dfs1(v),sz[u]+=sz[v]; 39 if(sz[v]>sz[son[u]]) son[u]=v; 40 } 41 } 42 } 43 void dfs2(int u,int t){ 44 top[u]=t,ls[u]=++num; 45 if(son[u]){ 46 dfs2(son[u],t); 47 for(int i=head[u];i;i=Next[i]){ 48 int v=ver[i]; 49 if(v!=fa[u]&&v!=son[u]) dfs2(v,v); 50 } 51 } 52 rs[u]=num; 53 } 54 inline int LCA(int u,int v){ 55 while(top[u]!=top[v]){ 56 if(dep[top[u]]<dep[top[v]]) swap(u,v); 57 u=fa[top[u]]; 58 } 59 return dep[u]<dep[v]?u:v; 60 } 61 inline int find(int u,int v){ 62 while(top[u]!=top[v]){ 63 if(fa[top[v]]==u) return top[v]; 64 v=fa[top[v]]; 65 } 66 return son[u]; 67 } 68 int ans[N],sum[N],c[N]; 69 inline void update(int l,int r,int val){ 70 for(;l<=n;l+=l&-l) c[l]+=val; 71 for(++r;r<=n;r+=r&-r) c[r]-=val; 72 } 73 inline int query(int x){ 74 int res=0; 75 for(;x;x-=x&-x) res+=c[x]; 76 return res; 77 } 78 struct plate{int x1,x2,y1,y2,val;}pl[N<<1]; 79 struct fruit{int x,y,k,id;}fr[N],tmp1[N],tmp2[N]; 80 struct node{int x,y1,y2,val,id;}eve[N*5]; 81 inline bool cmp(const plate &a,const plate &b){return a.val<b.val;} 82 inline bool cmp2(const node &a,const node &b){return a.x==b.x?a.id<b.id:a.x<b.x;} 83 void solve(int l,int r,int ql,int qr){ 84 if(ql>qr) return; 85 if(l==r){ 86 for(int i=ql;i<=qr;++i) ans[fr[i].id]=pl[l].val; 87 return; 88 } 89 int a=0,b=0,mid=l+r>>1,tot=0; 90 for(int i=l;i<=mid;++i) 91 eve[++tot]=(node){pl[i].x1,pl[i].y1,pl[i].y2,1,0}, 92 eve[++tot]=(node){pl[i].x2,pl[i].y1,pl[i].y2,-1,q+1}; 93 for(int i=ql;i<=qr;++i) 94 eve[++tot]=(node){fr[i].x,fr[i].y,0,0,i}; 95 sort(eve+1,eve+1+tot,cmp2); 96 for(int i=1;i<=tot;++i) 97 if(ql<=eve[i].id&&qr>=eve[i].id) sum[eve[i].id]=query(eve[i].y1); 98 else update(eve[i].y1,eve[i].y2,eve[i].val); 99 for(int i=ql;i<=qr;++i) 100 if(sum[i]>=fr[i].k) tmp1[++a]=fr[i]; 101 else tmp2[++b]=fr[i],tmp2[b].k-=sum[i]; 102 for(int i=1;i<=a;++i) fr[i+ql-1]=tmp1[i]; 103 for(int i=1;i<=b;++i) fr[i+ql+a-1]=tmp2[i]; 104 solve(l,mid,ql,ql+a-1),solve(mid+1,r,ql+a,qr); 105 } 106 int main(){ 107 //freopen("testdata.in","r",stdin); 108 n=read(),p=read(),q=read(); 109 for(int i=1;i<n;++i){ 110 int u=read(),v=read();add(u,v); 111 } 112 dfs1(1),dfs2(1,1); 113 for(int i=1;i<=p;++i){ 114 int u=read(),v=read(),e=read(),lca=LCA(u,v); 115 if(ls[u]>ls[v]) u^=v^=u^=v; 116 if(u!=lca) 117 pl[++cnt]=(plate){ls[u],rs[u],ls[v],rs[v],e}; 118 else{ 119 int x=find(u,v); 120 if(ls[x]>1) pl[++cnt]=(plate){1,ls[x]-1,ls[v],rs[v],e}; 121 if(rs[x]<n) pl[++cnt]=(plate){ls[v],rs[v],rs[x]+1,n,e}; 122 } 123 } 124 for(int i=1;i<=q;++i){ 125 int u=read(),v=read(),e=read(); 126 if(ls[u]>ls[v]) u^=v^=u^=v; 127 fr[i]=(fruit){ls[u],ls[v],e,i}; 128 } 129 sort(pl+1,pl+1+cnt,cmp),solve(1,cnt,1,q); 130 for(int i=1;i<=q;++i) print(ans[i]); 131 Ot(); 132 return 0; 133 }
转载于:https://www.cnblogs.com/bztMinamoto/p/9562138.html
bzoj4009: [HNOI2015]接水果(整体二分)相关推荐
- bzoj 4009: [HNOI2015]接水果 整体二分+k-d tree
Description 风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果. 由于她已经DT FC 了The big black, 她觉得这个游戏太简单了,于是发明了一个更 加 ...
- bzoj 4009 接水果 整体二分
Description 先给出一些盘子, 用路径x-y表示, 有权值 再有Q个询问, 表示水果, 用路径x-y表示 如果盘子是水果的子路径, 可以接住 对于每个水果, 输出可以接住它的盘子的第k小权 ...
- 【bzoj4009】[HNOI2015]接水果 DFS序+树上倍增+整体二分+树状数组
题目描述 给出一棵n个点的树,给定m条路径,每条路径有一个权值.q次询问求一个路径包含的所有给定路径中权值第k小的. 输入 第一行三个数 n和P 和Q,表示树的大小和盘子的个数和水果的个数. 接下来n ...
- P3242 [HNOI2015] 接水果(整体二分、扫描线)
P3242 [HNOI2015] 接水果 给定一棵树,定义给定了ppp个盘子,每个盘子是树上u,vu, vu,v两点的路径,且盘子有权值,定义水果,水果也是树上u,vu, vu,v两点间的路径. 有q ...
- 【HNOI2015】接水果【整体二分】【DFS序】【双区间转矩形】【扫描线】【树状数组】
传送门 题意:给定一个nnn个点的树,定义一个"盘子"为一个给定权值的路径,一个"水果"为一条路径,一个盘子可以接到水果当且仅当盘子的路径是水果的子路径.给出所 ...
- P3242 [HNOI2015] 接水果(整体二分、扫描线、dfs序)
解析 一道有点毒瘤的题 也是一道感觉真的可以出现在考场上的很综合的题 做的还可以 除了一开始把盘子和水果看反白写了各树套树之外 为什么盘子是水果的子路径啊 由于是做专题爬过来的多次询问区间第k小,想到 ...
- [HNOI2015] 接水果(倍增 + 整体二分)
problem luogu-P3242 solution 本题的难点在于如何判定路径之间是否覆盖. 这里我们尝试树常见的 dfs\text{dfs}dfs 序. 考虑 x−yx-yx−y 路径如果要覆 ...
- [XSY3112] 接水果(树上包含路径,整体二分,扫描线)
传送门 给出一棵nnn个点的树.接下来给出PPP条树上路径ai→bia_i\to b_iai→bi,及其权值cic_ici.最后有QQQ个询问,每个询问给出一条树上路径ui→viu_i\to v ...
- [洛谷P3242] [HNOI2015]接水果
洛谷题目链接:[HNOI2015]接水果 题目描述 风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果.由于她已经DT FC 了The big black, 她觉得这个游戏太简 ...
最新文章
- apache 安装与配置详细教程
- 无锁链表的c++实现
- Tomcat配置自签名https
- ReportViewer教程(15)-矩阵报表-4
- 如何将 Redis 的内存优化?
- 标准布局类(11中布局类)
- html登录页面代码Java,html简单登录页面代码
- 随机森林模型及案例(Python)
- 计算机在线题库系统,试题库管理系统.doc
- java 判断浏览器_Java怎么判断访问者使用的是360浏览器
- android集成华为push 6003错误,以及华为低版本crash问题
- clustalX2使用以及相关的问题
- 微擎支付返回商户单号_扫码枪轻轻一扫,瞬间扣款,支付背后的原理原来这么简单...
- Linux之RPM包的命名规则和包的依赖性
- 使用VS2013+MATLAB2016B开发MEX(64位)程序
- Cygwin 下载安装
- Altium Designer基础知识
- SSM毕设项目游泳馆管理系统851a0(java+VUE+Mybatis+Maven+Mysql)
- Crowding Counter 之 修改ShanghaiTech数据集
- 我为什么要选择traefik2做网关?