zoukankan      html  css  js  c++  java
  • 【bzoj3488】[ONTAK2010]Highways DFS序+树上倍增+树状数组

    题目描述

    一棵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(nlog 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
    " , ans[i] + 1);
    	return 0;
    }
    

     

  • 相关阅读:
    3372 选学霸
    3556 科技庄园
    1025 选菜
    UVA 437 The Tower of Babylon巴比伦塔
    3641 上帝选人
    tyvj P1175 机器人
    1692 子集和的目标值
    1689 建造高塔
    NOI2002 贪吃的九头龙
    NYOJ110 剑客决斗
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7725485.html
Copyright © 2011-2022 走看看