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 接水果的更多相关文章

  1. bzoj 4009 接水果 整体二分

    Description 先给出一些盘子, 用路径x-y表示, 有权值 再有Q个询问, 表示水果, 用路径x-y表示 如果盘子是水果的子路径, 可以接住 对于每个水果, 输出可以接住它的盘子的第k小权 ...

  2. BZOJ.4009.[HNOI2015]接水果(整体二分 扫描线)

    LOJ BZOJ 洛谷 又是一个三OJ rank1!=w= \(Description\) (还是感觉,为啥非要出那种题目背景啊=-=直接说不好么) 给定一棵树和一个路径集合(每条路径有一个权值).\ ...

  3. BZOJ 4009: [HNOI2015]接水果

    4009: [HNOI2015]接水果 Time Limit: 60 Sec  Memory Limit: 512 MBSubmit: 636  Solved: 300[Submit][Status] ...

  4. BZOJ 4009: [HNOI2015]接水果 (整体二分+扫描线 树状数组)

    整体二分+扫描线 树状数组 具体做法看这里a CODE #include <cctype> #include <cstdio> #include <cstring> ...

  5. BZOJ 3772: 精神污染 (dfs序+树状数组)

    跟 BZOJ 4009: [HNOI2015]接水果一样- CODE #include <set> #include <queue> #include <cctype&g ...

  6. BZOJ4009: [HNOI2015]接水果

    4009: [HNOI2015]接水果 Description 风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果. 由于她已经DT FC 了The big black,  她 ...

  7. [Luogu3242][HNOI2015]接水果

    Luogu 我今天做两道整体二分结果全都是BZOJ权限题??? sol 我们抓住"盘子的路径是水果的路径的子路径"这个条件. 考虑每一个盘子路径\((u,v)\),讨论它可以作为哪 ...

  8. [LOJ 2146][BZOJ 4873][Shoi2017]寿司餐厅

    [LOJ 2146][BZOJ 4873][Shoi2017]寿司餐厅 题意 比较复杂放LOJ题面好了qaq... Kiana 最近喜欢到一家非常美味的寿司餐厅用餐. 每天晚上,这家餐厅都会按顺序提供 ...

  9. BZOJ4009 & 洛谷3242 & LOJ2113:[HNOI2015]接水果——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4009 https://www.luogu.org/problemnew/show/P3242 ht ...

随机推荐

  1. MYSQL学习笔记3--mysql 2PC二阶段协义 与 日志闪回

    mysql两份日志: binlog :server innodb redo log:engine 两份日志顺序一致性:否则主备不一致 两份日志:原子性,同时都有,同时都无 2PC二阶段协义: 第一阶段 ...

  2. Xcode 5 安装coco2d-iphone

    从http://www.cocos2d-iphone.org/download/下载并解压缩最新版本的cocos2d,默认情况下会保存在 /Users/XXX/Downloads/cocos2d-ip ...

  3. Windows2012中安装PHP-5.6.20+Apache httpd2.4.18+Composer+Laravel+MySQL5.7

    下载软件包 PHP:  http://windows.php.net/downloads/releases/php-5.6.20-Win32-VC11-x64.zip Apache httpd:  h ...

  4. Memcache简介

    简介 Memcache是一个高性能的分布式的内存对象缓存系统,通过在内存里维护一个统一的巨大的hash表,它能够用来存储各种格式的数据,包括图像.视频.文件以及数据库检索的结果等.简单的说就是将数据调 ...

  5. Android 设计随便说说之简单实践(合理组合)

    上一篇(Android 设计随便说说之简单实践(模块划分))例举了应用商店设计来说明怎么做模块划分.模块划分主要依赖于第一是业务需求,具体是怎么样的业务.应用商店则包括两个业务,就是向用户展示appl ...

  6. java.util.zip压缩打包文件总结二: ZIP解压技术

    一.简述 解压技术和压缩技术正好相反,解压技术要用到的类:由ZipInputStream通过read方法对数据解压,同时需要通过CheckedInputStream设置冗余校验码,如: Checked ...

  7. 集成支付宝报一堆warning: (arm64) /Users/scmbuild/workspace/standard-pay/.....警告问题解决办法亲测可行!

  8. canvas之----浮动小球

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  9. 《ln命令》-linux命令五分钟系列之十八

    本原创文章属于<Linux大棚>博客,博客地址为http://roclinux.cn.文章作者为rocrocket. 为了防止某些网站的恶性转载,特在每篇文章前加入此信息,还望读者体谅. ...

  10. [Neural Networks] Dropout阅读笔记

    多伦多大学Hinton组 http://www.cs.toronto.edu/~rsalakhu/papers/srivastava14a.pdf 一.目的 降低overfitting的风险 二.原理 ...