题目描述

一棵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. linux命令系列-ln(软硬链接)

    linux命令 ln命令可以生成软链接和硬链接,也可叫做符号链接和实体链接. 有兴趣深入理解的可以查阅相关文档,一般的读者只需记住以下几点即可: .不管是软链接还是硬链接都不会额外增加磁盘空间(虽然实 ...

  2. 使用Cygwin在WIN系统下处理文本常用命令

    1.打开Cygwin,把需要处理的文本复制你的安装目录例如:D:\cygwin\home\Administrator 使用 ls命令查看根目录文件 2.现在我们就可以对1.txt文本进行操作, 3.我 ...

  3. 基于socketserver模块实现并发的套接字(tcp、udp)

    tcp服务端:import socketserver class MyHandler(socketserver.BaseRequestHandler): def handle(self): #通信循环 ...

  4. BootStrap的动态模态框及静态模态框

    1.要用bootStrap这个框架就必须要重载它的class类,也就是说class要一样 代码如下: 有疑问的可以在下面留言,欢迎大家一起交流 1.1动态模态框 <!DOCTYPE html&g ...

  5. linux总结及常用命令

    一.操作系统的作用: 1.是现代计算机系统中最基本和最重要的系统软件  2.承上启下的作用  3.向下对硬件操作进行封装  4.向上对用户和应用程序提供方便访问硬件的接口 二.不同领域的操作系统: 1 ...

  6. 糖果 南阳acm589

    糖果 时间限制:1000 ms  |  内存限制:65535 KB 难度:2   描述 topcoder工作室的PIAOYIi超级爱吃糖果,现在他拥有一大堆不同种类的糖果,他准备一口气把它们吃完,可是 ...

  7. Hive 函数之内置运算符

    本章介绍Hive的内置运算符.在Hive有四种类型的运算符: 关系运算符 算术运算符 逻辑运算符 复杂运算符 关系运算符 这些操作符被用来比较两个操作数.下表描述了在Hive中可用的关系运算符: 运算 ...

  8. 4368: [IOI2015]boxes纪念品盒

    4368: [IOI2015]boxes纪念品盒 链接 分析 链接 代码 #include<bits/stdc++.h> using namespace std; typedef long ...

  9. vs13发布web程序 iis上

    一.配置iis 1,找到控制面板--程序--启用或关闭Windows功能 2,从列表中选择Internet Infomation Services,并且把相应的功能条目勾选上,如果不清楚,可以全部选中 ...

  10. 操作Excel的宏

          有时候在Excel中,需要循环的算每一列的值,而这一列的值是某几列的求和或者某种运算后的结果,比如如下的C4=C3+B4      可以用一个宏来实现,宏代码如下: Dim i As In ...