题目描述

给出一棵n个点的树,给定m条路径,每条路径有一个权值。q次询问求一个路径包含的所有给定路径中权值第k小的。

输入

第一行三个数 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


题解

DFS序+树上倍增+整体二分+树状数组

咦这不是 Highways 那道题吗?只不过是变成一条路径包含的给定路径,求第k小。

那么按照那道题的方法,要求的就是包含询问点(包含其它路径的路径,询问路径)的给定矩形(被包含的路径,给定路径)中权值第k小的。

可以想到整体二分,统计一个点在多少个权值在$[l,mid]$范围内的矩形中出现过。可以使用离线+树状数组解决。

时间复杂度$O(n\log^2n)$

然而我的代码完全不可读。。。就别看了。。。

#include <cstdio>
#include <algorithm>
#define N 40010
using namespace std;
struct data
{
int x , y , z , v , w;
data() {}
data(int a , int b , int c , int d , int e) {x = a , y = b , z = c , v = d , w = e;}
bool operator<(const data &a)const {return x < a.x;}
}a[N * 3] , q[N * 2] , t[N * 2];
int n , head[N] , to[N << 1] , next[N << 1] , cnt , fa[N][20] , deep[N] , log[N] , pos[N] , last[N] , tp , tot , f[N] , val[N] , cc[N] , ans[N];
bool cmp(const data &a , const data &b)
{
return a.v < b.v;
}
inline void add(int x , int y)
{
to[++cnt] = y , next[cnt] = head[x] , head[x] = cnt;
}
void dfs(int x)
{
int i;
pos[x] = ++tp;
for(i = 1 ; (1 << i) <= deep[x] ; i ++ ) fa[x][i] = fa[fa[x][i - 1]][i - 1];
for(i = head[x] ; i ; i = next[i])
if(to[i] != fa[x][0])
fa[to[i]][0] = x , deep[to[i]] = deep[x] + 1 , dfs(to[i]);
last[x] = tp;
}
int find(int x , int y)
{
int i;
for(i = log[y] ; ~i ; i -- )
if((1 << i) <= y)
x = fa[x][i] , y -= (1 << i);
return x;
}
inline void update(int x , int a)
{
int i;
for(i = x ; i <= n ; i += i & -i) f[i] += a;
}
inline int query(int x)
{
int i , ans = 0;
for(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)
{
if(b > e) return;
int i;
if(L == R)
{
for(i = b ; i <= e ; i ++ ) ans[q[i].z] = L;
return;
}
int MID = (L + R) >> 1 , mid = l - 1 , p = l;
for(i = b ; i <= e ; i ++ ) cc[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(i = b ; i <= e ; i ++ )
{
while(p <= mid && a[p].x <= q[i].x) update(a[p].y , a[p].w) , update(a[p].z + 1 , -a[p].w) , p ++ ;
cc[q[i].z] += query(q[i].y);
}
while(p > l) p -- , update(a[p].y , -a[p].w) , update(a[p].z + 1 , a[p].w);
for(p = i = b ; i <= e ; i ++ ) if(val[q[i].z] <= cc[q[i].z]) t[p ++ ] = q[i];
for(p = i = e ; i >= b ; i -- ) if(val[q[i].z] > cc[q[i].z]) t[p -- ] = q[i];
for(i = b ; i <= e ; i ++ )
{
if(~cc[q[i].z] && val[q[i].z] > cc[q[i].z]) val[q[i].z] -= cc[q[i].z] , cc[q[i].z] = -1;
q[i] = t[i];
}
solve(b , p , l , mid , L , MID) , solve(p + 1 , e , mid + 1 , r , MID + 1 , R);
}
int main()
{
int m , k , i , x , y , z , t;
scanf("%d%d%d" , &n , &m , &k);
for(i = 2 ; i <= n ; i ++ ) scanf("%d%d" , &x , &y) , add(x , y) , add(y , x) , log[i] = log[i >> 1] + 1;
dfs(1);
for(i = 1 ; i <= m ; i ++ )
{
scanf("%d%d%d" , &x , &y , &z);
if(deep[x] > deep[y]) swap(x , y);
if(deep[x] < deep[y] && fa[t = find(y , deep[y] - deep[x] - 1)][0] == x)
{
a[++tot] = data(1 , pos[y] , last[y] , z , 1);
a[++tot] = data(pos[t] , pos[y] , last[y] , z , -1);
a[++tot] = data(last[t] + 1 , pos[y] , last[y] , z , 1);
}
else a[++tot] = data(pos[x] , pos[y] , last[y] , z , 1) , a[++tot] = data(last[x] + 1 , pos[y] , last[y] , z , -1);
}
for(i = 1 ; i <= k ; i ++ ) scanf("%d%d%d" , &x , &y , &val[i]) , q[i] = data(pos[x] , pos[y] , i , 0 , 0) , q[i + k] = data(pos[y] , pos[x] , i , 0 , 0);
sort(q + 1 , q + k * 2 + 1) , solve(1 , k * 2 , 1 , tot , 1 , 1000000000);
for(i = 1 ; i <= k ; i ++ ) printf("%d\n" , ans[i]);
return 0;
}

【bzoj4009】[HNOI2015]接水果 DFS序+树上倍增+整体二分+树状数组的更多相关文章

  1. hdu 3887 Counting Offspring(DFS序【非递归】+树状数组)

    题意: N个点形成一棵树.给出根结点P还有树结构的信息. 输出每个点的F[i].F[i]:以i为根的所有子结点中编号比i小的数的个数. 0<n<=10^5 思路: 方法一:直接DFS,进入 ...

  2. luogu3242 接水果 (整体二分+树状数组)

    考虑整体二分,问题就变成了每个(水果)路径有多少个满足条件(权值)的(盘子)子路径 考虑一个盘子(a,b)表示两端点(不妨设dfn[a]<dfn[b]),那么他能接到的水果(u,v)一定满足(不 ...

  3. 【bzoj4940】[Ynoi2016]这是我自己的发明 DFS序+树上倍增+莫队算法

    题目描述 给一个树,n 个点,有点权,初始根是 1. m 个操作,每次操作: 1. 将树根换为 x. 2. 给出两个点 x,y,从 x 的子树中选每一个点,y 的子树中选每一个点,如果两个点点权相等, ...

  4. 【BZOJ4009】[HNOI2015]接水果 DFS序+整体二分+扫描线+树状数组

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

  5. 【bzoj3488】[ONTAK2010]Highways DFS序+树上倍增+树状数组

    题目描述 一棵n个点的树,给定m条路径,q次询问包含一条路径的给定路径的个数+1 输入 The first line of input contains a single integer N(1< ...

  6. BZOJ3545&3551[ONTAK2010]Peaks——kruskal重构树+主席树+dfs序+树上倍增

    题目描述 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只 ...

  7. POJ 2763 Housewife Wind(DFS序+LCA+树状数组)

    Housewife Wind Time Limit: 4000MS   Memory Limit: 65536K Total Submissions: 11419   Accepted: 3140 D ...

  8. BZOJ3881 Coci2015Divljak(AC自动机+树上差分+树状数组)

    建出AC自动机及其fail树,每次给新加入的串在AC自动机上经过的点染色,问题即转化为子树颜色数.显然可以用dfs序转成序列问题树状数组套权值线段树解决,显然过不掉.事实上直接树上差分,按dfs序排序 ...

  9. BZOJ 3881 [COCI2015]Divljak (Trie图+Fail树+树链的并+树状数组维护dfs序)

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

随机推荐

  1. CSS3--j惊艳到你的新前端

    一.css3的选择器 1. 父子选择器 直接关系 .box>.com 2. 兄弟选择器 相邻关系 .box+.com <span>hello</span> <p&g ...

  2. 简易的vuex用法

    vuex是vue中用于管理全局状态的一个组件,用于不同组件之间的通信,下面将介绍它的简单用法 首先安装vue与vuex npm install vue npm install vuex --save ...

  3. hive 学习系列之七 hive 常用数据清洗函数

    1,case when 的利用,清洗诸如评分等的内容,用例如下. case when new.comment_grade = '五星商户' then 50 when new.comment_grade ...

  4. python 排列组合

    笛卡尔积(product): 假设集合A={a, b},集合B={0, 1, 2},则两个集合的笛卡尔积为{(a, 0), (a, 1), (a, 2), (b, 0), (b, 1), (b, 2) ...

  5. liunx下搭建python开发环境

    =============================================================================注意: 在linux下安装新的版本的pytho ...

  6. C# 设置程序最小化到任务栏右下角,鼠标左键单击还原,右键提示关闭程序

    首先设置程序最小化到任务栏右下角 先给窗口添加一个notifyIcon控件 为notifyIcon控件设置ICO图标(不设置图标将无法在任务栏显示) 给notifyIcon控件添加点击事件 然后是最小 ...

  7. 使用java多线程分批处理数据工具类

    最近由于业务需要,数据量比较大,需要使用多线程来分批处理,提高处理效率和能力,于是就写了一个通用的多线程处理工具,只需要实现自己的业务逻辑就可以正常使用,现在记录一下 主要是针对大数据量list,将l ...

  8. 谷歌面试官经典作品(CTCI)目录

    1.1 判断一个字符串中的字符是否唯一 1.2 字符串翻转 1.3 去除字符串中重复字符 1.8 利用已知函数判断字符串是否为另一字符串的子串 2.1 从链表中移除重复结点 2.2 实现一个算法从一个 ...

  9. 算法-----数组------ 数组中的第K个最大元素

    在未排序的数组中找到第 k 个最大的元素.请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素. 示例 1: 输入: [3,2,1,5,6,4] 和 k = 2 输出: 5 ...

  10. 高德API+.NET解决租房问题(可能是最可靠房源:上海互助租房)

    作者:李国宝链接:https://zhuanlan.zhihu.com/p/22113421来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. PS:最近点赞和关注的小伙伴 ...