传送门

给出一棵nnn个点的树。接下来给出PPP条树上路径ai→bia_i\to b_iai​→bi​,及其权值cic_ici​。最后有QQQ个询问,每个询问给出一条树上路径ui→viu_i\to v_iui​→vi​,问在包含ui→viu_i\to v_iui​→vi​的所有树上路径中(包含指ui→viu_i\to v_iui​→vi​是ai→bia_i\to b_iai​→bi​的子路径),权值第kkk小的路径权值是多少?

不妨设dep[u]<dep[v]dep[u]<dep[v]dep[u]<dep[v],
若lca(u,v)=ulca(u,v)=ulca(u,v)=u,记ppp是uuu在向vvv方向的儿子,
那么包含u→vu\to vu→v的路径a→ba\to ba→b一定满足:a∉subtreep,b∈subtreeva\not\in subtree_p,b\in subtree_va​∈subtreep​,b∈subtreev​
若lca(u,v)≠ulca(u,v)\not=ulca(u,v)​=u,
那么包含u→vu\to vu→v的路径a→ba\to ba→b一定满足:a∈subtreeu,b∈subtreeva\in subtree_u,b\in subtree_va∈subtreeu​,b∈subtreev​

也就是说,对于包含u→vu\to vu→v的路径a→ba\to ba→b,dfn[a],dfn[b]dfn[a],dfn[b]dfn[a],dfn[b]的取值范围是 一段或两端区间。
因此所有符合条件的路径a→ba\to ba→b可以用二维平面上的 一个或两个矩形 表示出来。

原题要求的就是所有包含询问点矩形中权值第kkk小的。

考虑整体二分,统计一个点在多少个 权值在[l,r][l,r][l,r]内的矩形 中出现过。用扫描线解决。

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=80010;
struct Edge{int v,nxt;}edge[N];
int n,m,q,cnt,head[N];
int fa[N][20],dep[N],ind,dfn[N],lst[N];
int tot,ans[N],sum[N];
struct Rectangle{int xd,xu,yd,yu,v;}rect[N];
bool operator < (Rectangle a,Rectangle b){return a.v<b.v;}
struct Point{int x,y,k,id;}pt[N],tmp1[N],tmp2[N];
struct Line{int x,yd,yu,v,id;}line[N];
bool operator < (Line a,Line b){return a.x==b.x?a.id<b.id:a.x<b.x;}
struct Bit{int val[N];void modify(int l,int r,int v){for(int i=l;i<=n;i+=(i&(-i))) val[i]+=v;for(int i=r+1;i<=n;i+=(i&(-i))) val[i]-=v;}int query(int x){int res=0;for(;x;x-=(x&(-x))) res+=val[x];return res;}
}T;
void add(int u,int v){edge[++cnt].v=v;edge[cnt].nxt=head[u];head[u]=cnt;
}
void dfs(int u){dfn[u]=++ind;for(int i=0;fa[u][i];i++) fa[u][i+1]=fa[fa[u][i]][i];for(int i=head[u];i;i=edge[i].nxt){int v=edge[i].v;if(v==fa[u][0]) continue;fa[v][0]=u;dep[v]=dep[u]+1;dfs(v);}lst[u]=ind;
}
int jump(int u,int dis){for(int i=18;dis;i--){if(dis>=(1<<i)){dis-=(1<<i);u=fa[u][i];}}return u;
}
int LCA(int u,int v){if(dep[u]<dep[v]) swap(u,v);u=jump(u,dep[u]-dep[v]);if(u==v) return u;for(int i=18;i>=0;i--) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];return fa[u][0];
}
void solve(int l,int r,int st,int ed){if(st>ed) return;if(l==r){for(int i=st;i<=ed;i++) ans[pt[i].id]=rect[l].v;return;}int mid=(l+r)>>1,siz=0;for(int i=l;i<=mid;i++){line[++siz]=(Line){rect[i].xd,rect[i].yd,rect[i].yu,1,0};line[++siz]=(Line){rect[i].xu,rect[i].yd,rect[i].yu,-1,n+1};}for(int i=st;i<=ed;i++) line[++siz]=(Line){pt[i].x,pt[i].y,0,0,i};sort(line+1,line+siz+1);for(int i=1;i<=siz;i++){if(st<=line[i].id&&line[i].id<=ed) sum[line[i].id]=T.query(line[i].yd);else T.modify(line[i].yd,line[i].yu,line[i].v);}int a=0,b=0;for(int i=st;i<=ed;i++){if(sum[i]>=pt[i].k) tmp1[++a]=pt[i];else tmp2[++b]=(Point){pt[i].x,pt[i].y,pt[i].k-sum[i],pt[i].id};}for(int i=st;i<=st+a-1;i++) pt[i]=tmp1[i-st+1];for(int i=st+a;i<=ed;i++) pt[i]=tmp2[i-st-a+1];solve(l,mid,st,st+a-1);solve(mid+1,r,st+a,ed);
}
int main(){scanf("%d%d%d",&n,&m,&q);for(int i=1;i<n;i++){int a,b;scanf("%d%d",&a,&b);add(a,b);add(b,a);}dfs(1);for(int i=1;i<=m;i++){int a,b,c;scanf("%d%d%d",&a,&b,&c);int u=LCA(a,b);if(dfn[a]>dfn[b]) swap(a,b);if(u!=a) rect[++tot]=(Rectangle){dfn[a],lst[a],dfn[b],lst[b],c};else{int w=jump(b,dep[b]-dep[a]-1);rect[++tot]=(Rectangle){1,dfn[w]-1,dfn[b],lst[b],c};if(lst[w]<n) rect[++tot]=(Rectangle){dfn[b],lst[b],lst[w]+1,n,c};}}sort(rect+1,rect+tot+1);for(int i=1;i<=q;i++){int a,b,k;scanf("%d%d%d",&a,&b,&k);if(dfn[a]>dfn[b]) swap(a,b);pt[i]=(Point){dfn[a],dfn[b],k,i};}solve(1,tot,1,q);for(int i=1;i<=q;i++) printf("%d\n",ans[i]);return 0;
}

[XSY3112] 接水果(树上包含路径,整体二分,扫描线)相关推荐

  1. bzoj 4009 接水果 整体二分

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

  2. 【bzoj4009】[HNOI2015]接水果 DFS序+树上倍增+整体二分+树状数组

    题目描述 给出一棵n个点的树,给定m条路径,每条路径有一个权值.q次询问求一个路径包含的所有给定路径中权值第k小的. 输入 第一行三个数 n和P 和Q,表示树的大小和盘子的个数和水果的个数. 接下来n ...

  3. bzoj4009: [HNOI2015]接水果(整体二分)

    题目描述 风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果.由于她已经DT FC 了The big black, 她觉得这个游戏太简单了,于是发明了一个更加难的版本. 首先有 ...

  4. bzoj 4009: [HNOI2015]接水果 整体二分+k-d tree

    Description 风见幽香非常喜欢玩一个叫做 osu!的游戏,其中她最喜欢玩的模式就是接水果. 由于她已经DT FC 了The big black, 她觉得这个游戏太简单了,于是发明了一个更 加 ...

  5. P3242 [HNOI2015] 接水果(整体二分、扫描线)

    P3242 [HNOI2015] 接水果 给定一棵树,定义给定了ppp个盘子,每个盘子是树上u,vu, vu,v两点的路径,且盘子有权值,定义水果,水果也是树上u,vu, vu,v两点间的路径. 有q ...

  6. [HNOI2015] 接水果(倍增 + 整体二分)

    problem luogu-P3242 solution 本题的难点在于如何判定路径之间是否覆盖. 这里我们尝试树常见的 dfs\text{dfs}dfs 序. 考虑 x−yx-yx−y 路径如果要覆 ...

  7. 【HNOI2015】接水果【整体二分】【DFS序】【双区间转矩形】【扫描线】【树状数组】

    传送门 题意:给定一个nnn个点的树,定义一个"盘子"为一个给定权值的路径,一个"水果"为一条路径,一个盘子可以接到水果当且仅当盘子的路径是水果的子路径.给出所 ...

  8. P3242 [HNOI2015] 接水果(整体二分、扫描线、dfs序)

    解析 一道有点毒瘤的题 也是一道感觉真的可以出现在考场上的很综合的题 做的还可以 除了一开始把盘子和水果看反白写了各树套树之外 为什么盘子是水果的子路径啊 由于是做专题爬过来的多次询问区间第k小,想到 ...

  9. 【BZOJ1146】【CTSC2008】网络管理 [整体二分]

    网络管理 Time Limit: 50 Sec  Memory Limit: 162 MB [Submit][Status][Discuss] Description M公司是一个非常庞大的跨国公司, ...

最新文章

  1. Spring Cloud Sleuth 服务跟踪 将跟踪信息存储到数据库
  2. 自定义sort函数第三个参数的规则
  3. ajax调用后台java类_ajax调用java后台方法是什么
  4. Netty技术细节源码分析-ByteBuf的内存泄漏原因与检测
  5. php phar,PHP中phar(PHP Archive)包的创建并使用
  6. Eclipse 调试器
  7. 【scrapy windows环境下安装遇到的问题】
  8. 二等水准数据平差_自编单次二等水准平差计算表
  9. nginx作为静态资源服务器的配置
  10. PCL:三维点云概述(一)
  11. Css Gird网格布局详细介绍
  12. Macbook M1 安装node(亲测)
  13. 照片编辑后怎么恢复到之前
  14. 安卓图书信息管理系统
  15. Java精品项目源码第53期流浪动物管理系统
  16. Android磨皮算法的实现 renderScript实现表面模糊
  17. Effie:陪你守候那些观影岁月
  18. (纯前台)读取、解析并展示xls/xlsx
  19. 萧乾升:4.20黄金白银TD最新走势分析后续布局
  20. Qt-绘制圆饼图等-转摘

热门文章

  1. 软件测试基础知识bbst,摘自James Bach对软件测试新手的建议
  2. 7-8 最优服务次序问题 (10 分)
  3. Java当中 报错 没有有任何类型 的外层实例可访问
  4. 数据结构 快速排序(详解)
  5. [剑指offer]面试题22:栈的压入、弹出序列
  6. 前端demo_【前端3分钟】Script Error产生的原因和解法
  7. 列名无效如何解决_XSKY ClickHouse如何实现存算分离
  8. word List44
  9. CF1422F Boring Queries(ST表 + 主席树)
  10. Educational Codeforces Round 17 E. Radio stations cdq分治 + 树状数组