BZOJ 4009 接水果
Description
风见幽香非常喜欢玩一个叫做osu!的游戏,其中她最喜欢玩的模式就是接水果。
由于她已经DT FC了The big black, 她觉得这个游戏太简单了,于是发明了一个更加难的版本。首先有一个地图,是一棵由\(n\)个顶点、\(n-1\)条边组成的树。这颗树上有\(P\)个盘子,每个盘子实际上是一条路径,并且每个盘子还有一个权值。第\(i\)个盘子就是顶点\(a_{i}\)到顶点\(b_{i}\)的路径(由于是树,所以从\(a_{i}\)到\(b_{i}\)的路径是唯一的),权值为\(c_{i}\)。接下来依次会有\(Q\)个水果掉下来,每个水果本质上也是一条路径,第\(i\)个水果是从顶点\(u_{i}\)到顶点\(v_{i}\)的路径。幽香每次需要选择一个盘子去接当前的水果:一个盘子能接住一个水果,当且仅当盘子的路径是水果的路径的子路径。这里规定:从\(a\)到\(b\)的路径与从\(b\)到\(a\)的路径是同一条路径。当然为了提高难度,对于第\(i\)个水果,你需要选择能接住它的所有盘子中,权值第\(k_{i}\)小的那个盘子,每个盘子可重复使用(没有使用次数的上限:一个盘子接完一个水果后,后面还可继续接其他水果,只要它是水果路径的子路径)。幽香认为这个游戏很难,你能轻松解决给她看吗?
Input
第一行三个数\(n,P\)和\(Q\),表示树的大小和盘子的个数和水果的个数。
接下来\(n-1\)行,每行两个数\(a,b\),表示树上的\(a\)和\(b\) 之间有一条边。树中顶点按\(1\)到\(n\)标号。接下来\(P\)行,每行三个数\(a,b,c\),表示路径为\(a\)到\(b\)、权值为\(c\)的盘子,其中\(0 \le c \le 10^{9},a \neq b\)。
接下来\(Q\)行,每行三个数\(u,v,k\),表示路径为\(u\)到\(v\)的水果,其中\(u \neq v\),你需要选择第\(k\)小的盘子,第\(k\)小一定存在。
Output
对于每个果子,输出一行表示选择的盘子的权值。
Sample Input
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
Sample Output
442139372
333042360
442139372
283254485
283254485
217394434
217394434
217394434
217394434
217394434
Hint
\(N,P,Q \le 40000\)。
整体二分。对于区间\(l \sim r\),二分值域\(mid\),将\(\le mid\)的盘子加入,每个水果的\(k\)与其路径上存在的盘子数进行比较,若多了该询问往左区间\(l \sim mid\)递归,否则往右区间\(mid+1 \sim r\)递归。
现在的问题就是如何判定每个水果的\(k\)与其路径上存在的盘子数的大小关系。考虑每个盘子,覆盖的路径为\(a_{i}\)到\(b_{i}\)(\(dep_{a_{i}} < dep_{b_{i}}\)),那么这个盘子所贡献的水果只有可能两种情况:
\(1.b_{i}\)在\(a_{i}\)的子树内,那么水果的两个端点\(u,v\)必须一个\(b_{i}\)的子树内,一个在\(a_{i}\)的子树外(可以包括\(a_{i}\))。
\(2.\)否则,两个点必须一个在\(a_{i}\)的子树内,一个在\(b_{i}\)的子树内。
看到有子树的东西,马上想到dfs序。由于这个dfs序是一段连续的区间,所以我们可以将盘子根据dfs序抽象成为矩形(情况一上两个不相交的矩形,情况二是一个矩形),将水果抽象成为一个点,每次检验即询问点被多少矩形所覆盖。扫描线+树状数组即可解决。
注意:矩形必须保证\(x\)坐标小于\(y\)坐标。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
using namespace std;
#define maxn (40010)
int N,P,Q,side[maxn],next[maxn*2],toit[maxn*2],dep[maxn],tree[maxn];
int L[maxn],R[maxn],ans[maxn],f[maxn][20],Ts,cnt,tot,have[maxn],sum[maxn];
struct SCAN
{
int X,Y1,Y2,sign,be;
friend inline bool operator <(const SCAN &a,const SCAN &b) { return a.X != b.X?a.X < b.X:a.sign<b.sign; }
}bac[8*maxn],save[maxn][4];
inline int jump(int a,int step)
{
for (int i = 0;step;step >>= 1,++i) if (step&1) a = f[a][i];
return a;
}
inline int lowbit(int a) { return a&-a; }
inline void modify(int a,int b) { for (;a <= N;a += lowbit(a)) tree[a] += b; }
inline int calc(int a) { int ret = 0; for (;a;a -= lowbit(a)) ret += tree[a]; return ret; }
struct NODE
{
int a,b,c,id;
friend inline bool operator <(const NODE &x,const NODE &y) { return x.c < y.c; }
inline void read(int i) { scanf("%d %d %d",&a,&b,&c); id = i; }
inline void update() { if (L[a] > L[b]) swap(a,b); }
inline void ins1() { bac[++tot] = (SCAN){L[a],L[b],L[b],0,id}; }
inline void ins2() { for (int i = 0;i < have[id];++i) bac[++tot] = save[id][i]; }
inline void change()
{
if (L[b] >= L[a]&&L[b] <= R[a])
{
int son = jump(b,dep[b]-dep[a]-1);
if (L[son] > 1)
{
save[id][have[id]++] = (SCAN){1,L[b],R[b],-1,id};
save[id][have[id]++] = (SCAN){L[son]-1,L[b],R[b],1,id};
}
if (R[son] < N)
{
save[id][have[id]++] = (SCAN){L[b],R[son]+1,N,-1,id};
save[id][have[id]++] = (SCAN){R[b],R[son]+1,N,1,id};
}
}
else
{
save[id][have[id]++] = (SCAN){L[a],L[b],R[b],-1,id};
save[id][have[id]++] = (SCAN){R[a],L[b],R[b],1,id};
}
}
}path[maxn],query[maxn],tmp[maxn];
inline void add(int a,int b) { next[++cnt] = side[a]; side[a] = cnt; toit[cnt] = b; }
inline void ins(int a,int b) { add(a,b); add(b,a); }
inline void dfs(int now)
{
L[now] = ++Ts;
for (int i = 1;(1 << i) <= dep[now];++i) f[now][i] = f[f[now][i-1]][i-1];
for (int i = side[now];i;i = next[i])
if (toit[i] != f[now][0])
f[toit[i]][0] = now,dep[toit[i]] = dep[now]+1,dfs(toit[i]);
R[now] = Ts;
}
inline void census(int ql,int qr,int pl,int pr,int &ll,int &rr)
{
tot = 0;
for (int i = pl;i <= pr;++i) path[i].ins2();
for (int i = ql;i <= qr;++i) query[i].ins1();
sort(bac+1,bac+tot+1);
for (int i = 1;i <= tot;++i)
{
if (!bac[i].sign) sum[bac[i].be] = calc(bac[i].Y1);
else modify(bac[i].Y1,-bac[i].sign),modify(bac[i].Y2+1,bac[i].sign);
}
for (int i = ql;i <= qr;++i)
{
if (sum[query[i].id] >= query[i].c) tmp[++ll] = query[i];
else query[i].c -= sum[query[i].id],tmp[--rr] = query[i];
sum[query[i].id] = 0;
}
for (int i = ql;i <= qr;++i) query[i] = tmp[i];
for (int i = 1;i <= tot;++i)
if (bac[i].sign) modify(bac[i].Y1,bac[i].sign),modify(bac[i].Y2+1,-bac[i].sign);
}
inline void work(int ql,int qr,int pl,int pr)
{
if (ql > qr) return;
if (pl == pr)
{
for (int i = ql;i <= qr;++i) ans[query[i].id] = path[pl].c;
return;
}
int ll = ql-1,rr = qr+1,mid = (pl + pr)>>1;
census(ql,qr,pl,mid,ll,rr);
work(ql,ll,pl,mid); work(rr,qr,mid+1,pr);
}
int main()
{
freopen("fruit.in","r",stdin);
freopen("fruit.out","w",stdout);
scanf("%d %d %d",&N,&P,&Q);
for (int i = 1,a,b;i < N;++i) scanf("%d %d",&a,&b),ins(a,b);
dfs(1);
for (int i = 1;i <= P;++i) path[i].read(i),path[i].update(),path[i].change();
sort(path+1,path+P+1);
for (int i = 1;i <= Q;++i) query[i].read(i),query[i].update();
work(1,Q,1,P);
for (int i = 1;i <= Q;++i) printf("%d\n",ans[i]);
fclose(stdin); fclose(stdout);
return 0;
}
BZOJ 4009 接水果的更多相关文章
- bzoj 4009 接水果 整体二分
Description 先给出一些盘子, 用路径x-y表示, 有权值 再有Q个询问, 表示水果, 用路径x-y表示 如果盘子是水果的子路径, 可以接住 对于每个水果, 输出可以接住它的盘子的第k小权 ...
- BZOJ.4009.[HNOI2015]接水果(整体二分 扫描线)
LOJ BZOJ 洛谷 又是一个三OJ rank1!=w= \(Description\) (还是感觉,为啥非要出那种题目背景啊=-=直接说不好么) 给定一棵树和一个路径集合(每条路径有一个权值).\ ...
- BZOJ 4009: [HNOI2015]接水果
4009: [HNOI2015]接水果 Time Limit: 60 Sec Memory Limit: 512 MBSubmit: 636 Solved: 300[Submit][Status] ...
- BZOJ 4009: [HNOI2015]接水果 (整体二分+扫描线 树状数组)
整体二分+扫描线 树状数组 具体做法看这里a CODE #include <cctype> #include <cstdio> #include <cstring> ...
- BZOJ 3772: 精神污染 (dfs序+树状数组)
跟 BZOJ 4009: [HNOI2015]接水果一样- CODE #include <set> #include <queue> #include <cctype&g ...
- BZOJ4009: [HNOI2015]接水果
4009: [HNOI2015]接水果 Description 风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果. 由于她已经DT FC 了The big black, 她 ...
- [Luogu3242][HNOI2015]接水果
Luogu 我今天做两道整体二分结果全都是BZOJ权限题??? sol 我们抓住"盘子的路径是水果的路径的子路径"这个条件. 考虑每一个盘子路径\((u,v)\),讨论它可以作为哪 ...
- [LOJ 2146][BZOJ 4873][Shoi2017]寿司餐厅
[LOJ 2146][BZOJ 4873][Shoi2017]寿司餐厅 题意 比较复杂放LOJ题面好了qaq... Kiana 最近喜欢到一家非常美味的寿司餐厅用餐. 每天晚上,这家餐厅都会按顺序提供 ...
- BZOJ4009 & 洛谷3242 & LOJ2113:[HNOI2015]接水果——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=4009 https://www.luogu.org/problemnew/show/P3242 ht ...
随机推荐
- [D3] 11. Basic D3 chart interactivity on(), select(this), classed(class, trueorfalse)
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8&quo ...
- 文件IO 练习题
3.1 当读/写磁盘文件时,本章中描述的函数是否具有缓冲机制?请说明原因. 3.1 所有的磁盘 I/O 都要经过内核的块缓冲区(也称为内核的缓冲区高速缓存),唯一例 外的是对原始磁盘设备的 I/O,但 ...
- window mac iPhone 三种比较相似的字体
win: 华文黑体 mac:stheiti iphone:heitisc-light heitisc-medium
- Git学习笔记(一)
刚开始学Git,记录下来,讹误之处还望指教. 安装好git之后,有两个东东,如图: git bash 表示是命令行操作. git GUI 表示是图形化操作.但是这个界面用起来不方便,另一个图形化操作工 ...
- LCA问题
基本概念 LCA:树上的最近公共祖先,对于有根树T的两个结点u.v,最近公共祖先LCA(T,u,v)表示一个结点x,满足x是u.v的祖先且x的深度尽可能大. RMQ:区间最小值查询问题.对于长度为n的 ...
- Codeforces Round #310 (Div. 2)--B
http://codeforces.com/problemset/problem/556/B 题意:给定n个数字且都小于n,然后每次循环第2k+1个数字+1,第2k个数字减一,k=0,1,2...n/ ...
- js--小结⑤
js中的for循环,while循环,do...while循环和C语言的一模一样 有几个问题要提醒一下的是 1. null是对象,即object undefined是undefined d ...
- CSS之关于clearfix--清除浮动
一,什么是.clearfix 你只要到Google或者Baidu随便一搜"css清除浮动",就会发现很多网站都讲到"盒子清除内部浮动时可以用到.clearfix" ...
- SQL Server2008 附加数据库失败 错误代码5120
由于目录权限不够导致 ,解决办法:将文件所在的文件夹增加everyone 并且赋予完全控制权限问题解决
- asp.net中WebForm.aspx与类文件分离使用
第一步:新建一个web项目和类库,新建一个页面和映射类文件: 第二步:在页面中,删除默认映射类,添加服务器控件. 1.更改映射类命名空间: 原: <%@ Page Language=" ...