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$的影响,然后用树状数组存储前缀和并查询
//minamoto
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[<<],*p1=buf,*p2=buf;
inline int read(){
#define num ch-'0'
char ch;bool flag=;int res;
while(!isdigit(ch=getc()))
(ch=='-')&&(flag=true);
for(res=num;isdigit(ch=getc());res=res*+num);
(flag)&&(res=-res);
#undef num
return res;
}
char sr[<<],z[];int C=-,Z;
inline void Ot(){fwrite(sr,,C+,stdout),C=-;}
inline void print(int x){
if(C><<)Ot();if(x<)sr[++C]=,x=-x;
while(z[++Z]=x%+,x/=);
while(sr[++C]=z[Z],--Z);sr[++C]='\n';
}
const int N=;
int ver[N<<],Next[N<<],head[N],tot=;
int val[N],fa[N],dep[N],son[N],sz[N],ls[N],rs[N],top[N];
int n,p,q,cnt,num;
inline void add(int u,int v){
ver[++tot]=v,Next[tot]=head[u],head[u]=tot;
ver[++tot]=u,Next[tot]=head[v],head[v]=tot;
}
void dfs1(int u){
sz[u]=,dep[u]=dep[fa[u]]+;
for(int i=head[u];i;i=Next[i]){
int v=ver[i];
if(v!=fa[u]){
fa[v]=u,dfs1(v),sz[u]+=sz[v];
if(sz[v]>sz[son[u]]) son[u]=v;
}
}
}
void dfs2(int u,int t){
top[u]=t,ls[u]=++num;
if(son[u]){
dfs2(son[u],t);
for(int i=head[u];i;i=Next[i]){
int v=ver[i];
if(v!=fa[u]&&v!=son[u]) dfs2(v,v);
}
}
rs[u]=num;
}
inline int LCA(int u,int v){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]]) swap(u,v);
u=fa[top[u]];
}
return dep[u]<dep[v]?u:v;
}
inline int find(int u,int v){
while(top[u]!=top[v]){
if(fa[top[v]]==u) return top[v];
v=fa[top[v]];
}
return son[u];
}
int ans[N],sum[N],c[N];
inline void update(int l,int r,int val){
for(;l<=n;l+=l&-l) c[l]+=val;
for(++r;r<=n;r+=r&-r) c[r]-=val;
}
inline int query(int x){
int res=;
for(;x;x-=x&-x) res+=c[x];
return res;
}
struct plate{int x1,x2,y1,y2,val;}pl[N<<];
struct fruit{int x,y,k,id;}fr[N],tmp1[N],tmp2[N];
struct node{int x,y1,y2,val,id;}eve[N*];
inline bool cmp(const plate &a,const plate &b){return a.val<b.val;}
inline bool cmp2(const node &a,const node &b){return a.x==b.x?a.id<b.id:a.x<b.x;}
void solve(int l,int r,int ql,int qr){
if(ql>qr) return;
if(l==r){
for(int i=ql;i<=qr;++i) ans[fr[i].id]=pl[l].val;
return;
}
int a=,b=,mid=l+r>>,tot=;
for(int i=l;i<=mid;++i)
eve[++tot]=(node){pl[i].x1,pl[i].y1,pl[i].y2,,},
eve[++tot]=(node){pl[i].x2,pl[i].y1,pl[i].y2,-,q+};
for(int i=ql;i<=qr;++i)
eve[++tot]=(node){fr[i].x,fr[i].y,,,i};
sort(eve+,eve++tot,cmp2);
for(int i=;i<=tot;++i)
if(ql<=eve[i].id&&qr>=eve[i].id) sum[eve[i].id]=query(eve[i].y1);
else update(eve[i].y1,eve[i].y2,eve[i].val);
for(int i=ql;i<=qr;++i)
if(sum[i]>=fr[i].k) tmp1[++a]=fr[i];
else tmp2[++b]=fr[i],tmp2[b].k-=sum[i];
for(int i=;i<=a;++i) fr[i+ql-]=tmp1[i];
for(int i=;i<=b;++i) fr[i+ql+a-]=tmp2[i];
solve(l,mid,ql,ql+a-),solve(mid+,r,ql+a,qr);
}
int main(){
//freopen("testdata.in","r",stdin);
n=read(),p=read(),q=read();
for(int i=;i<n;++i){
int u=read(),v=read();add(u,v);
}
dfs1(),dfs2(,);
for(int i=;i<=p;++i){
int u=read(),v=read(),e=read(),lca=LCA(u,v);
if(ls[u]>ls[v]) u^=v^=u^=v;
if(u!=lca)
pl[++cnt]=(plate){ls[u],rs[u],ls[v],rs[v],e};
else{
int x=find(u,v);
if(ls[x]>) pl[++cnt]=(plate){,ls[x]-,ls[v],rs[v],e};
if(rs[x]<n) pl[++cnt]=(plate){ls[v],rs[v],rs[x]+,n,e};
}
}
for(int i=;i<=q;++i){
int u=read(),v=read(),e=read();
if(ls[u]>ls[v]) u^=v^=u^=v;
fr[i]=(fruit){ls[u],ls[v],e,i};
}
sort(pl+,pl++cnt,cmp),solve(,cnt,,q);
for(int i=;i<=q;++i) print(ans[i]);
Ot();
return ;
}
bzoj4009: [HNOI2015]接水果(整体二分)的更多相关文章
- [BZOJ4009][HNOI2015]接水果(整体二分)
[HNOI2015]接水果 时间限制:60s 空间限制:512MB 题目描述 风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果. 由于她已经DT FC 了The b ...
- [bzoj4009] [HNOI2015]接水果 整体二分+扫描线+dfs序+树状数组
Description 风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果. 由于她已经DT FC 了The big black, 她觉得这个游戏太简单了,于是发明了一个更 加 ...
- bzoj4009 [HNOI2015]接水果 整体二分+扫描线+树状数组+dfs序
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4009 题解 考虑怎样的情况就会有一个链覆盖另一个链. 设被覆盖的链为 \(a - b\),覆盖 ...
- BZOJ4009:[HNOI2015]接水果(整体二分版)
浅谈离线分治算法:https://www.cnblogs.com/AKMer/p/10415556.html 题目传送门:https://lydsy.com/JudgeOnline/problem.p ...
- BZOJ.4009.[HNOI2015]接水果(整体二分 扫描线)
LOJ BZOJ 洛谷 又是一个三OJ rank1!=w= \(Description\) (还是感觉,为啥非要出那种题目背景啊=-=直接说不好么) 给定一棵树和一个路径集合(每条路径有一个权值).\ ...
- BZOJ 4009: [HNOI2015]接水果 (整体二分+扫描线 树状数组)
整体二分+扫描线 树状数组 具体做法看这里a CODE #include <cctype> #include <cstdio> #include <cstring> ...
- [HNOI2015]接水果[整体二分]
[HNOI2015]接水果 给出一个树上路径集合\(S\) 多次询问\(x,y\)中的\(k\)小值 如果你问我数列上那么我会 树上的话 树上差分了吧直接?- 令 \(st_x<st_y\) 1 ...
- 2018.10.02 bzoj4009: [HNOI2015]接水果(整体二分)
传送门 整体二分好题. 考虑水果被盘子接住的条件. 不妨设水果表示的路径为(x1,y1)(x_1,y_1)(x1,y1),盘子表示的为(x2,y2)(x_2,y_2)(x2,y2) 不妨设df ...
- [HNOI2015][bzoj4009] 接水果 [整体二分+扫描线]
题面 传送门 思路 本题其实有在线做法......但是太难写了,退而求其次写了离线 基本思路就是,考虑一个盘子以及它能接到的所有水果 可以发现,这个水果的端点一定在这个盘子两端的"子树&qu ...
随机推荐
- Android Stadio导入Android工程项目,只有Edit Configurations的解决办法
这几天导入老的Android工程项目,导入后,也不发红也不报错,但是Run这一项没有可运行的App,就只有一个Edit Configurations.经过查询后,发现运行一下Sync Project ...
- SQLite进阶-15.触发器
目录 触发器(Trigger) 触发器(Trigger)的要点: 触发器应用 查看触发器 删除触发器 触发器(Trigger) 触发器(Trigger)是数据库的回调函数,它会在指定的数据库事件发生时 ...
- Python中几个必须知道的函数
Python中自带了几个比较有意思的函数,一般在面试或者笔试基础的时候会问到,其中3个就是map.filter.reduce函数. 1.map(function, iterable) 它第一个要传的元 ...
- cmake 升级
cmake 升级 1下载 cmake-3.1.0.tar.gz2.解压 3.执行 ./configure 4.执行 make 5. 执行 sudo make install 6.添加环境变量 ...
- [python]近日 用3种库 实现简单的窗口 的回顾~
最近任务:利用python 实现以下4个窗口弹窗. 信息提示框 文本输入框(需在窗口消失后,返回 用户输入的值) 文件选择(需在窗口消失后, 返回 用户选择的文件名的全路径) 文件夹选择(需在窗口消失 ...
- docker-registry的定制和性能分析
docker-index Web UI Meta-data 元数据存储(附注.星级.公共库清单) 访问认证 token管理 存储镜像.以及镜像层的家族谱系 没有用户账户数据 不知道用户的账户和安全性 ...
- Excel2016 保存\复制 卡死问题解决
遇到的问题: 工作中经常碰到一些Excel表, 复制一行, 再粘贴要等5s以上才能显示成功. 保存一下文档, 也会出现页面白屏卡死的情况, 经过网上多个帖子进行操作依旧无解, 最后找到了自己的方法得以 ...
- java学习要想精炼掌握应运的必备知识(博文来源于网络)
一: 编程基础 不管是C还是C++,不管是Java还是PHP,想成为一名合格的程序员,基本的数据结构和算法基础还是要有的.下面几篇文章从思想到实现,为你梳理出常用的数据结构和经典算法. 1-1 常用数 ...
- 怎样理解document的快捷方式属性
所谓 "快捷方式属性" , 也就是说它们不是必须的, 只是在操作dom时可以更为方便地获取. 主要有下面8个: 1. 获取当前文档所属的window对象: document.def ...
- [Vue]vue-router的push和replace的区别
1.this.$router.push() 描述:跳转到不同的url,但这个方法会向history栈添加一个记录,点击后退会返回到上一个页面. 2.this.$router.replace() 描述: ...