Description

风见幽香非常喜欢玩一个叫做 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 小的那个盘子,每个盘子可重复使用(没有使用次数

的上限:一个盘子接完一个水果后,后面还可继续接其他水果,只要它是水

果路径的子路径)。幽香认为这个游戏很难,你能轻松解决给她看吗?

Input

第一行三个数 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 小一定存在。

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<=40000。

Source

Solution

本题简化题意:n个结点的树,给定m条带权值的路径(端点不重合),q个询问,每个询问给定一条路径,查询m条路径中所有它的子路径的权值第k小。

首先如果两个路径有包含关系,那么是可以用dfs序的区间表示的,具体看代码,所以我们可以把集合中的两个dfs序区间看成二维平面上的一个矩形,然后询问看成一个点,这样题意就转化成了包含一个点的矩形中权值第k大的,然后我们二分答案,就成了判定性问题,判断够不够k个,这样就可以直接用扫描线做啦。然后二分的话复杂度爆炸,所以要整体二分,在整体二分时候的细节见代码,用树状数组+排序就可以解决二维数点问题。

Code

#include <bits/stdc++.h>
#define N 40005
using namespace std;
struct nod
{
int x,y,z,v,w;
nod(int a=0,int b=0,int c=0,int d=0,int e=0){x=a,y=b,z=c,v=d,w=e;}
bool operator<(const nod &a)const{return x<a.x;}
}a[N*3],q[N*2],t[N*2];
int n,m,k,x,y,z,g,he[N],to[N<<1],ne[N<<1],cnt,anc[N][20],dep[N],in[N],ou[N],I,tot,f[N],val[N],vl[N],ans[N];
bool cmp(nod a,nod b){return a.v<b.v;}
void add(int x,int y){to[++cnt]=y,ne[cnt]=he[x],he[x]=cnt;}
void dfs(int x)
{
in[x]=++I;for(int i=1;i<=15;i++) anc[x][i]=anc[anc[x][i-1]][i-1];
for(int i=he[x],y;i;i=ne[i]) if((y=to[i])!=anc[x][0]) anc[y][0]=x,dep[y]=dep[x]+1,dfs(y);
ou[x]=I;
}
int find(int x,int y){for(int i=15;~i;i--) if((1<<i)<=y) x=anc[x][i],y-=(1<<i);return x;}
void upd(int x,int a){for(int i=x;i<=n;i+=i&-i) f[i]+=a;}
int que(int x){int ans=0;for(int i=x;i;i-=i&-i) ans+=f[i];return ans;}
void solve(int b,int e,int l,int r,int L,int R)//be:询问 lr:修改 LR:权值
{
if(b>e) return;
if(L==R){for(int i=b;i<=e;i++) ans[q[i].z]=L;return;}//权值只有一种,直接记录区间内的答案
int MID=(L+R)>>1,mid=l-1,p=l;//整体二分时,只用扫左一半的修改,然后如果数量不够就在以后的右边进行递归处理,够就在以后的左边进行递归处理
for(int i=b;i<=e;i++) vl[q[i].z]=0;sort(a+l,a+r+1,cmp);
while(mid<r&&a[mid+1].v<=MID) mid++;sort(a+l,a+mid+1);
for(int i=b;i<=e;i++)
{
while(p<=mid&&a[p].x<=q[i].x) upd(a[p].y,a[p].w),upd(a[p].z+1,-a[p].w),p++;
vl[q[i].z]+=que(q[i].y);//对每个点累加覆盖它的矩阵
}
while(p>l) p--,upd(a[p].y,-a[p].w),upd(a[p].z+1,a[p].w);//还原
for(int i=(p=b);i<=e;i++) if(val[q[i].z]<=vl[q[i].z]) t[p++]=q[i];//够的
for(int i=(p=e);i>=b;i--) if(val[q[i].z]>vl[q[i].z]) t[p--]=q[i];//不够的
for(int i=b;i<=e;q[i]=t[i],i++) if(~vl[q[i].z]&&val[q[i].z]>vl[q[i].z]) val[q[i].z]-=vl[q[i].z],vl[q[i].z]=-1;//减去已经覆盖的
solve(b,p,l,mid,L,MID),solve(p+1,e,mid+1,r,MID+1,R);
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=2;i<=n;i++) scanf("%d%d",&x,&y),add(x,y),add(y,x);
dfs(1);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&z);
if(dep[x]>dep[y]) swap(x,y);
if(dep[x]<dep[y]&&anc[g=find(y,dep[y]-dep[x]-1)][0]==x)//x是y的祖先,xy路径上x的直系儿子子树之外->y子树之内的路径都可以
{
a[++tot]=nod(1,in[y],ou[y],z,1);
a[++tot]=nod(in[g],in[y],ou[y],z,-1);
a[++tot]=nod(ou[g]+1,in[y],ou[y],z,1);//右端点是n,所以不用添加
}
else a[++tot]=nod(in[x],in[y],ou[y],z,1),a[++tot]=nod(ou[x]+1,in[y],ou[y],z,-1);//x和y没有祖先关系,x的子树内->y的子树内的路径都可以
}
for(int i=1;i<=k;i++) scanf("%d%d%d",&x,&y,&val[i]),q[i]=nod(in[x],in[y],i,0,0),q[i+k]=nod(in[y],in[x],i,0,0);
sort(q+1,q+k*2+1),solve(1,k*2,1,tot,1,1000000000);
for(int i=1;i<=k;i++)printf("%d\n",ans[i]);
}

[bzoj4009] [HNOI2015]接水果 整体二分+扫描线+dfs序+树状数组的更多相关文章

  1. bzoj4009 [HNOI2015]接水果 整体二分+扫描线+树状数组+dfs序

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=4009 题解 考虑怎样的情况就会有一个链覆盖另一个链. 设被覆盖的链为 \(a - b\),覆盖 ...

  2. 计蒜客A1998 Ka Chang (分块+dfs序+树状数组)

    题意 给你一个\(1e5\)的有点权的树,有\(1e5\)个操作: 1.给第\(x\)层的点加上\(y\) 2.求以\(x\)为根的子树的点权和 思路 首先处理出层数为x的所有点 操作2一般都是用df ...

  3. HDU 3887:Counting Offspring(DFS序+树状数组)

    http://acm.hdu.edu.cn/showproblem.php?pid=3887 题意:给出一个有根树,问对于每一个节点它的子树中有多少个节点的值是小于它的. 思路:这题和那道苹果树是一样 ...

  4. HDU 5293 Tree chain problem 树形dp+dfs序+树状数组+LCA

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5293 题意: 给你一些链,每条链都有自己的价值,求不相交不重合的链能够组成的最大价值. 题解: 树形 ...

  5. Codeforces Round #225 (Div. 1) C. Propagating tree dfs序+树状数组

    C. Propagating tree Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/383/p ...

  6. BZOJ 2434: [Noi2011]阿狸的打字机( AC自动机 + DFS序 + 树状数组 )

    一个串a在b中出现, 那么a是b的某些前缀的后缀, 所以搞出AC自动机, 按fail反向建树, 然后查询(x, y)就是y的子树中有多少是x的前缀. 离线, 对AC自动机DFS一遍, 用dfs序+树状 ...

  7. 【bzoj3881】[Coci2015]Divljak AC自动机+树链的并+DFS序+树状数组

    题目描述 Alice有n个字符串S_1,S_2...S_n,Bob有一个字符串集合T,一开始集合是空的. 接下来会发生q个操作,操作有两种形式: “1 P”,Bob往自己的集合里添加了一个字符串P. ...

  8. [BZOJ1103][POI2007]大都市meg dfs序+树状数组

    Description 在经济全球化浪潮的影响下,习惯于漫步在清晨的乡间小路的邮递员Blue Mary也开始骑着摩托车传递邮件了.不过,她经常回忆起以前在乡间漫步的情景.昔日,乡下有依次编号为1..n ...

  9. 2018.10.20 NOIP模拟 巧克力(trie树+dfs序+树状数组)

    传送门 好题啊. 考虑前面的32分,直接维护后缀trietrietrie树就行了. 如果#号不在字符串首? 只需要维护第一个#前面的字符串和最后一个#后面的字符串. 分开用两棵trie树并且维护第一棵 ...

随机推荐

  1. confd test

    vi /etc/confd/confd.toml backend = "consul"confdir = "/etc/confd"log-level = &qu ...

  2. leetcode 27 Romove element

    描述: 删除指定元素.不是真的删除,要求把不符合的元素前移. 解决: 非常简单. int removeElement(vector<int>& nums, int val) { ) ...

  3. JavaScript事件 DOMNodeInserted DOMNodeRemoved

    JavaScript与HTML之间的交互是通过事件实现的.事件,就是文档或浏览器窗口中发生的一些特定交互的瞬间.可以使用侦听器(或处理程序)来预订事件,以便事件发生时执行相应的代码. 13.1 事件流 ...

  4. JAVA里的CAS算法简析

    Atomic 从JDK5开始, java.util.concurrent包里提供了很多面向并发编程的类. 使用这些类在多核CPU的机器上会有比较好的性能.主要原因是这些类里面大多使用(失败-重试方式的 ...

  5. GlobalMemoryStatusEx获取内存

    typedef struct _MEMORYSTATUSEX { DWORD dwLength; DWORD dwMemoryLoad; DWORDLONG ullTotalPhys; DWORDLO ...

  6. 添加普通用户为sudo用户

    https://www.linuxidc.com/Linux/2017-01/139361.htm 1.打开sudoers文件 切换到root用户下,cd root,运行visudo命令,visudo ...

  7. ANGULAR 2 BITS: UNIFIED DEPENDENCY INJECTION

    Angular 1.x has two APIs for injecting dependencies into a directive. These APIs are not interchange ...

  8. Mysql索引会失效的几种情况分析(转)

    出处:http://www.jb51.net/article/50649.htm 索引并不是时时都会生效的,比如以下几种情况,将导致索引失效: 1.如果条件中有or,即使其中有条件带索引也不会使用(这 ...

  9. C++中const在函数中的用法

    1.const放在函数前面 如果我们的函数的返回值是以 指针形式 返回的,如果在函数前面加上const修饰,则表示指针指向的内容是不能被改变的,并且接收返回值的 指针变量必须是const修饰的,例如: ...

  10. ros kinect calibration

    RGB camera Bring up the OpenNI driver: roslaunch openni_launch openni.launch Now follow the standard ...