zoukankan      html  css  js  c++  java
  • 【bzoj4285】使者 CDQ分治+扫描线+树状数组

    题目描述

    给出一棵树,支持三种操作:
    加入一条路径;
    删除一条路径;
    查询有多少条路径包含某给出路径。

    输入

    第一行一个正整数n。
    接下来n - 1 行每行两个整数u, v,表示一条星际航道连接行星 u 与行星 v。
    接下来一行一个正整数m,表示已经被发现的跳跃点个数。
    接下来m行每行两个整数s, t,表示一个跳跃点连接行星 s与行星 t。
    接下来一行一个正整数q,表示事件个数。
    接下来q 行每行为以下三种事件中的一种:
    “1 x y” :表示有一个连接行星x与行星 y的跳跃点被发现了;
    “2 x y” :表示有一个连接行星 x 与行星 y 的跳跃点崩溃了(保证存在这样
    一个跳跃点) ;
    “3 x y” :表示有一个外星使者想从行星x到行星 y去搜集情报。

    输出

    对于每个外星使者输出一行一个整数, 表示这个外星使者可以选择的不同路径条数。

    样例输入

    13
    1 2
    1 3
    1 4
    2 5
    5 9
    5 10
    5 11
    10 13
    3 6
    4 7
    4 8
    7 12
    6
    2 4
    10 12
    9 8
    6 7
    3 11
    7 10
    5
    1 1 5
    3 5 4
    2 7 10
    2 10 12
    3 5 4

    样例输出

    3
    1


    题解

    CDQ分治+扫描线+树状数组

    诶这题挺熟悉?这不是 【bzoj3772】精神污染 吗?一份良心点的题解: 【bzoj3488】[ONTAK2010]Highways DFS序+树上倍增+树状数组 。

    那这题怎么做呢?按照同样的方法转化,就相当于:在二维平面上,支持:插入一个点,删除一个点,查询矩形内的点数。

    由于可以离线,因此可以使用CDQ分治。

    具体方法:将矩形查询转化为4个二维前缀和相加减。第一维时间自然有序;递归过程中维护第二维(点的第一维坐标)递增,按扫描线顺序进行左半部分的修改、右半部分的查询,并使用归并排序合并;第三维在树状数组中查询。

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

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 100010
    using namespace std;
    struct data
    {
    	int x , y , opt , v;
    	data() {}
    	data(int a , int b , int c , int d) {x = a , y = b , opt = c , v = d;}
    }a[N * 5] , t[N * 5];
    int head[N] , to[N << 1] , next[N << 1] , cnt , fa[N][20] , log[N] , deep[N] , pos[N] , last[N] , tot , p , f[N] , n , ans[N];
    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] = ++tot;
    	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] = tot;
    }
    inline int find(int x , int y)
    {
    	int i;
    	for(i = log[y] ; ~i ; i -- )
    		if(y >= (1 << i))
    			x = fa[x][i] , y -= (1 << i);
    	return x;
    }
    inline void push(int x , int y , int z)
    {
    	a[++p] = data(pos[x] , pos[y] , 0 , z) , a[++p] = data(pos[y] , pos[x] , 0 , z);
    }
    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 l , int r)
    {
    	if(l == r) return;
    	int mid = (l + r) >> 1 , p1 = l , p2 = mid + 1 , p3 = l;
    	solve(l , mid) , solve(mid + 1 , r);
    	while(p3 <= r)
    	{
    		if(p2 > r || (p1 <= mid && a[p1].x <= a[p2].x))
    		{
    			if(!a[p1].opt) update(a[p1].y , a[p1].v);
    			t[p3 ++ ] = a[p1 ++ ];
    		}
    		else
    		{
    			if(a[p2].opt) ans[a[p2].v] += a[p2].opt * query(a[p2].y);
    			t[p3 ++ ] = a[p2 ++ ];
    		}
    	}
    	for(p1 = l ; p1 <= mid ; p1 ++ )
    		if(!a[p1].opt)
    			update(a[p1].y , -a[p1].v);
    	for(p1 = l ; p1 <= r ; p1 ++ ) a[p1] = t[p1];
    }
    int main()
    {
    	int m , q , c = 0 , i , t , x , y;
    	scanf("%d" , &n);
    	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);
    	scanf("%d" , &m);
    	for(i = 1 ; i <= m ; i ++ ) scanf("%d%d" , &x , &y) , push(x , y , 1);
    	scanf("%d" , &q);
    	for(i = 1 ; i <= q ; i ++ )
    	{
    		scanf("%d%d%d" , &t , &x , &y);
    		if(t == 1) push(x , y , 1);
    		else if(t == 2) push(x , y , -1);
    		else
    		{
    			c ++ ;
    			if(deep[x] < deep[y]) swap(x , y);
    			if(deep[x] > deep[y] && fa[t = find(x , deep[x] - deep[y] - 1)][0] == y)
    			{
    				a[++p] = data(pos[x] - 1 , pos[t] - 1 , -1 , c) , a[++p] = data(pos[x] - 1 , last[t] , 1 , c) , a[++p] = data(pos[x] - 1 , n , -1 , c);
    				a[++p] = data(last[x] , pos[t] - 1 , 1 , c) , a[++p] = data(last[x] , last[t] , -1 , c) , a[++p] = data(last[x] , n , 1 , c);
    			}
    			else
    			{
    				a[++p] = data(pos[x] - 1 , pos[y] - 1 , 1 , c) , a[++p] = data(pos[x] - 1 , last[y] , -1 , c);
    				a[++p] = data(last[x] , pos[y] - 1 , -1 , c) , a[++p] = data(last[x] , last[y] , 1 , c);
    			}
    		}
    	}
    	solve(1 , p);
    	for(i = 1 ; i <= c ; i ++ ) printf("%d
    " , ans[i]);
    	return 0;
    }
    

     

  • 相关阅读:
    Codeforces Round #401 (Div. 2)【A,B,C,D】
    HDU2874【LCA(模板)】
    ZOJ2898【折半搜索】
    zoj2901【DP·二进制优化】
    萌新笔记之鸽巢原理及其应用
    codeforces 547B【单调栈】
    Codeforces631C【栈维护+瞎搞】
    每天一节组合数学
    HDU 1506【单调栈】
    HDU 3410【单调栈】
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/8066669.html
Copyright © 2011-2022 走看看