题目描述

一棵n个点的树,给定m条路径,q次询问包含一条路径的给定路径的个数+1

输入

The first line of input contains a single integer N(1<=N<=100000) - the number of cities in Byteland. Cities are numbered from 1 to n . Each of the next N -1 lines contains two integers Ai, Bi(1<=Ai,Bi<=N) meaning that cities Ai and Biare connected by a road. 
The next line contains an integer M(1<=M<=100000) - the number of highways. Each of the next m lines contains a description of a single highway. The next line contains an integer Q (1<=Q<=500000) - the number of queries. Each of the next Q lines contains a description of a query. Both highways and queries are given in the same format as the roads.

输出

Your program should output exactly Q lines. The i-th line should contain the number of routes in the i-th query.

样例输入

9
1 2
2 3
4 2
1 5
5 6
7 5
7 8
9 7
4
2 5
3 4
6 4
8 3
4
4 9
2 5
1 6
1 7

样例输出

1
4
2
2


题解

DFS序+树状数组

咦这不是 精神污染 那道题吗?然而我那道题写得太丑了。。。

我们不妨换个思路:考虑一条路径被什么样的路径所包含。

当两个点x和y没有祖先关系时,显然包含它的路径的两个端点应该分别在x和y的子树内。

当x和y具有祖先关系时,不妨设x是y的祖先,那么设x到y路径上x的儿子为z,那么包含它的路径的两个端点应该分别在z的子树外和y的子树内。

那么就可以使用DFS序把两个端点的取值范围转化为DFS序上的一段或两段区间,其中找儿子z的过程可以使用树上倍增实现。

于是把每个路径x-y看作平面上的点(pos[x],pos[y])(pos[x]表示x在DFS序中的位置),那么包含一条给定路径的所有路径就转化为至多2个矩形。

所以每次询问要求的就是矩形内的点的数目,可以使用离线+树状数组解决。把每个矩形拆成前缀相减的4个点,把所有点按x坐标排序,然后使用树状数组维护y坐标的前缀和即可。

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

#include <cstdio>
#include <cctype>
#include <algorithm>
#define N 100010
using namespace std;
struct data
{
int x , y , v , id;
data() {}
data(int a , int b , int c , int d) {x = a , y = b , v = c , id = d;}
bool operator<(const data &a)const {return x < a.x;}
}a[N << 1] , q[N * 30];
int n , head[N] , to[N << 1] , next[N << 1] , cnt , fa[N][20] , deep[N] , log[N] , pos[N] , last[N] , tp , f[N] , tot , ans[N * 5];
inline char nc()
{
static char buf[100000] , *p1 , *p2;
return p1 == p2 && (p2 = (p1 = buf) + fread(buf , 1 , 100000 , stdin) , p1 == p2) ? EOF : *p1 ++ ;
}
inline int read()
{
int ret = 0; char ch = nc();
while(!isdigit(ch)) ch = nc();
while(isdigit(ch)) ret = ((ret + (ret << 2)) << 1) + (ch ^ '0') , ch = nc();
return ret;
}
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;
}
inline 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 i;
for(i = x ; i <= n ; i += i & -i) f[i] ++ ;
}
inline int query(int x)
{
int i , ans = 0;
for(i = x ; i ; i -= i & -i) ans += f[i];
return ans;
}
int main()
{
int m , k , i , x , y , z , p;
n = read();
for(i = 2 ; i <= n ; i ++ ) x = read() , y = read() , add(x , y) , add(y , x) , log[i] = log[i >> 1] + 1;
dfs(1);
m = read();
for(i = 1 ; i <= m ; i ++ ) x = read() , y = read() , a[i] = data(pos[x] , pos[y] , 0 , 0) , a[i + m] = data(pos[y] , pos[x] , 0 , 0);
k = read();
for(i = 1 ; i <= k ; i ++ )
{
x = read() , y = read();
if(deep[x] < deep[y]) swap(x , y);
if(deep[x] > deep[y] && fa[z = find(x , deep[x] - deep[y] - 1)][0] == y)
{
q[++tot] = data(pos[x] - 1 , pos[z] - 1 , -1 , i) , q[++tot] = data(pos[x] - 1 , last[z] , 1 , i) , q[++tot] = data(pos[x] - 1 , n , -1 , i);
q[++tot] = data(last[x] , pos[z] - 1 , 1 , i) , q[++tot] = data(last[x] , last[z] , -1 , i) , q[++tot] = data(last[x] , n , 1 , i);
}
else
{
q[++tot] = data(pos[x] - 1 , pos[y] - 1 , 1 , i) , q[++tot] = data(pos[x] - 1 , last[y] , -1 , i);
q[++tot] = data(last[x] , pos[y] - 1 , -1 , i) , q[++tot] = data(last[x] , last[y] , 1 , i);
}
}
sort(a + 1 , a + 2 * m + 1) , sort(q + 1 , q + tot + 1);
for(p = i = 1 ; i <= tot ; i ++ )
{
while(p <= m * 2 && a[p].x <= q[i].x) update(a[p ++ ].y);
ans[q[i].id] += q[i].v * query(q[i].y);
}
for(i = 1 ; i <= k ; i ++ ) printf("%d\n" , ans[i] + 1);
return 0;
}

【bzoj3488】[ONTAK2010]Highways DFS序+树上倍增+树状数组的更多相关文章

  1. 洛谷P2414 阿狸的打字机【AC自动机】【fail树】【dfs序】【树状数组】

    居然真的遇上了这种蔡队题.瑟瑟发抖. 题目背景 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机. 题目描述 打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母.经阿 ...

  2. 【dfs序+AC自动机+树状数组】BZOJ2434-[Noi2011]阿狸的打字机

    [题目大意] 输入一个字符串,其中:(1)a..z:在字符串末尾添加当前字符(2)P:输出当前字符串(3)B:从当前字符串末尾删去一个字符. 给出m组查询,输出第i个输出的字符串在第j个输出的字符串内 ...

  3. 【手动开栈】【dfs序】【树状数组】【Tarjan】bzoj2819 Nim

    考虑树状数组区间修改(只对其子树的答案有影响)点查询,每个点记录的是它到根路径上的权值异或和. 答案时query(L)^query(R)^a[lca]. 这种方法在支持区间加法.减法的树上询问的时候可 ...

  4. Codeforces 375D Tree and Queries(DFS序+莫队+树状数组)

    题目链接  Tree and Queries 题目大意  给出一棵树和每个节点的颜色.每次询问$vj, kj$ 你需要回答在以$vj$为根的子树中满足条件的的颜色数目, 条件:具有该颜色的节点数量至少 ...

  5. 【dfs序】【树状数组】bzoj1103 [POI2007]大都市meg

    预处理出每个点到根节点的土路数,插到一个树状数组里,然后每次修改只会对子树中的节点造成影响,于是相当于区间修改.点查询了. #include<cstdio> using namespace ...

  6. HDU 6203 ping ping ping [LCA,贪心,DFS序,BIT(树状数组)]

    题目链接:[http://acm.hdu.edu.cn/showproblem.php?pid=6203] 题意 :给出一棵树,如果(a,b)路径上有坏点,那么(a,b)之间不联通,给出一些不联通的点 ...

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

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

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

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

  9. [bzoj4034][HAOI2015]树上操作——树状数组+dfs序

    Brief Description 您需要设计一种数据结构支持以下操作: 把某个节点 x 的点权增加 a . 把某个节点 x 为根的子树中所有点的点权都增加 a . 询问某个节点 x 到根的路径中所有 ...

随机推荐

  1. Percona-Tookit工具包之pt-visual-explain

      Preface       As usual we will check the MySQL executed plan of SQL query by execute "explain ...

  2. Java反射的两种使用方法

    1.创建User.java package com.tao.test; public class User { private String name; private int id; public ...

  3. visio studio code 用chrom启动打开本地html

    { // 使用 IntelliSense 了解相关属性. // 悬停以查看现有属性的描述. // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linki ...

  4. es6几个新增语法的使用----数组

    //数组的累加方法 let arr=[1,2,3]; let sum=arr.reduce((prev,cur)=>{ return prev+cur; }) console.log(sum)/ ...

  5. pig分组统计例子

    1.选取数据样本 在pig安装目录下有一个文件tutorial/data/excite-small.log,其中的数据分为3列,中间用制表符分隔,第一列为用户ID,第二列为Unix时间戳,第三列为查询 ...

  6. uva 253 - Cube painting(相同骰子)

    习题4-4 骰子涂色(Cube painting, UVa 253) 输入两个骰子,判断二者是否等价.每个骰子用6个字母表示,如图4-7所示. 图4-7 骰子涂色 例如rbgggr和rggbgr分别表 ...

  7. Sql Server 表间对应关系

    <1>.关联映射:一对多/多对一 存在最普遍的映射关系,简单来讲就如球员与球队的关系:一对多:从球队角度来说一个球队拥有多个球员 即为一对多多对一:从球员角度来说多个球员属于一个球队 即为 ...

  8. .net core 新建一个web api 的步骤 初级

    1.使用VS2017 选择 .net core web应用程序. 2.选择web api(空). 3.如果需要用iis express调试,则需要修改 program.cs. 4.在Controlle ...

  9. 洛谷P2307 迷宫

    怎么又是一道叫迷宫的题呀QWQ 题目链接 这道题主要是对并查集的考察,需要注意的坑点在于有可能存在的不止一个联通块. 我们只需要对输入的两个数据进行判断,如果在一个集合中证明有多条路则输出0,如果不在 ...

  10. CC3200模块的内存地址划分和bootloader(一)

    1. CC3200的内存地址划分非常特殊,如果没测试的话,很容易懵逼.我们先看芯片手册里面的内存地址.芯片的RAM是256KB,下图的0x2000 0000-0x2003 FFFF,正好是256KB. ...