• 【bzoj4103】[Thu Summer Camp 2015]异或运算 可持久化Trie树


    题目描述

    给定长度为n的数列X={x1,x2,...,xn}和长度为m的数列Y={y1,y2,...,ym},令矩阵A中第i行第j列的值Aij=xi xor  yj,每次询问给定矩形区域i∈[u,d],j∈[l,r],找出第k大的Aij。

    输入

    第一行包含两个正整数n,m,分别表示两个数列的长度

    第二行包含n个非负整数xi
    第三行包含m个非负整数yj
    第四行包含一个正整数p,表示询问次数
    随后p行,每行均包含5个正整数,用来描述一次询问,每行包含五个正整数u,d,l,r,k,含义如题意所述。

    输出

    共p行,每行包含一个非负整数,表示此次询问的答案。

    样例输入

    3 3
    1 2 4
    7 6 5
    3
    1 2 1 2 2
    1 2 1 3 4
    2 3 2 3 4

    样例输出

    6
    5
    1


    题解

    可持久化Trie树

    考虑到$n$只有1000,$p$只有500,因此可以对每一组询问暴力处理每行。

    然后就相当于是在多棵可持久化01Trie树上求第k大,可以采用类似权值线段树的二分方法,计算最终最高位为1的数的个数,如果小于等于k,则说明最终答案最高位为1,把树根设为能够使最高位为1的儿子;否则说明最终答案最高位为0,把树根设为能够使最高位为0的儿子。然后同理处理每一位即可。具体可以参见代码。

    时间复杂度$O(31m+31pn)$。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define N 300010
    using namespace std;
    int a[1010] , root[N] , c[2][N * 35] , si[N * 35] , tot , r1[1010] , r2[1010];
    inline void insert(int v , int x , int &y)
    {
    	int i , u = ++tot;
    	bool t;
    	y = u , si[y] = si[x] + 1;
    	for(i = 1 << 30 ; i ; i >>= 1)
    		t = v & i , c[t ^ 1][u] = c[t ^ 1][x] , c[t][u] = ++tot , x = c[t][x] , u = c[t][u] , si[u] = si[x] + 1;
    }
    inline int query(int u , int d , int l , int r , int k)
    {
    	int i , j , sum , ans = 0;
    	bool t;
    	for(i = u ; i <= d ; i ++ ) r1[i] = root[l - 1] , r2[i] = root[r];
    	for(i = 1 << 30 ; i ; i >>= 1)
    	{
    		sum = 0;
    		for(j = u ; j <= d ; j ++ )
    			t = a[j] & i , sum += si[c[t ^ 1][r2[j]]] - si[c[t ^ 1][r1[j]]];
    		if(k <= sum)
    		{
    			ans += i;
    			for(j = u ; j <= d ; j ++ )
    				t = a[j] & i , r1[j] = c[t ^ 1][r1[j]] , r2[j] = c[t ^ 1][r2[j]];
    		}
    		else
    		{
    			k -= sum;
    			for(j = u ; j <= d ; j ++ )
    				t = a[j] & i , r1[j] = c[t][r1[j]] , r2[j] = c[t][r2[j]];
    		}
    	}
    	return ans;
    }
    int main()
    {
    	int n , m , q , i , u , d , l , r , k;
    	scanf("%d%d" , &n , &m);
    	for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &a[i]);
    	for(i = 1 ; i <= m ; i ++ ) scanf("%d" , &u) , insert(u , root[i - 1] , root[i]);
    	scanf("%d" , &q);
    	while(q -- ) scanf("%d%d%d%d%d" , &u , &d , &l , &r , &k) , printf("%d
    " , query(u , d , l , r , k));
    	return 0;
    }
    

     

  • 相关阅读:
    Qt之QFileSystemWatcher
    Qt之qSetMessagePattern
    物联网操作系统HelloX V1.80测试版发布
    CoreOS Linux available in China
    等火车
    HTTP 简介
    建造模式Builder
    MariaDB exists 学习
    javascript 中 typeof 的使用
    Java字符串null相加
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/7509893.html
Copyright © 2020-2023  润新知