bzoj4103【THUSC2015】异或运算

4103: [Thu Summer Camp 2015]异或运算

Time Limit: 20 Sec  Memory Limit: 512 MB

Submit: 359  Solved: 188

[Submit][Status][Discuss]

Description

给定长度为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。

Input

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

第二行包含n个非负整数xi

第三行包含m个非负整数yj

第四行包含一个正整数p,表示询问次数

随后p行,每行均包含5个正整数,用来描述一次询问,每行包含五个正整数u,d,l,r,k,含义如题意所述。

Output

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

Sample Input

3 3

1 2 4

7 6 5

3

1 2 1 2 2

1 2 1 3 4

2 3 2 3 4

Sample Output

6

5

1

HINT

对于100%的数据,0<=Xi,Yj<2^31,

1<=u<=d<=n<=1000,

1<=l<=r<=m<=300000,

1<=k<=(d-u+1)*(r-l+1),

1<=p<=500

Source

鸣谢佚名上传

可持久化Trie树

发现n和m的范围差距很大,所以n可以暴力枚举,m用可持久化Trie树提取区间。

题目要求a数组一段区间的数和b数组一段区间的数异或的k大值,考虑从高位到低位贪心,每次尽量选1,否则选0。

于是从高到低枚举每一位,询问a数组每一个元素对应那棵Trie树上节点大小,进而判断这一位能否填1。

注意:a数组每一个数对应的Trie树要分别保存。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#define F(i,j,n) for(int i=j;i<=n;i++)
#define D(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define N 1005
#define M 300005
using namespace std;
int n,m,q,cnt,x_1,x_2,y_1,y_2,k;
int a[N],b[M];
int sz[M*35],c[M*35][2],rt[M];
struct data{int x,y;}p[N];
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
void insert(int x,int &y,int val,int tmp)
{
	y=++cnt;sz[y]=sz[x]+1;
	c[y][0]=c[x][0];c[y][1]=c[x][1];
	if (tmp==-1) return;
	int t=(val>>tmp)&1;
	insert(c[x][t],c[y][t],val,tmp-1);
}
int solve(int k,int tmp)
{
	if (tmp==-1) return 0;
	int sum=0;
	F(i,x_1,x_2)
	{
		int t=(a[i]>>tmp)&1;
		sum+=sz[c[p[i].y][t^1]]-sz[c[p[i].x][t^1]];
	}
	if (sum>=k)
	{
		F(i,x_1,x_2)
		{
			int t=(a[i]>>tmp)&1;
			p[i].x=c[p[i].x][t^1];
			p[i].y=c[p[i].y][t^1];
		}
		return solve(k,tmp-1)+(1<<tmp);
	}
	else
	{
		F(i,x_1,x_2)
		{
			int t=(a[i]>>tmp)&1;
			p[i].x=c[p[i].x][t];
			p[i].y=c[p[i].y][t];
		}
		return solve(k-sum,tmp-1);
	}
}
int main()
{
	n=read();m=read();
	F(i,1,n) a[i]=read();
	F(i,1,m) b[i]=read();
	F(i,1,m) insert(rt[i-1],rt[i],b[i],30);
	q=read();
	while (q--)
	{
		x_1=read();x_2=read();y_1=read();y_2=read();k=read();
		F(i,x_1,x_2) p[i].x=rt[y_1-1],p[i].y=rt[y_2];
		printf("%d\n",solve(k,30));
	}
}
时间: 2024-12-28 00:22:20

bzoj4103【THUSC2015】异或运算的相关文章

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

[BZOJ4103][Thu Summer Camp 2015]异或运算 Description 给定长度为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. Input 第一行包含两个正整数n,m,分别表示两个数列的长度 第二行包含n个非负整数xi 第三行包含m个非负整数yj 第四行包含一个正整数p,表示询问次数 随后p行,每行

HDU 5175 Misaki&#39;s Kiss again (异或运算,公式变形)

Misaki's Kiss again Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 201    Accepted Submission(s): 57 Problem Description After the Ferries Wheel, many friends hope to receive the Misaki's kiss

异或运算的性质及用途

 1.两个数的交换  利用异或运算可以实习一种简单的不使用第三个数的交换方式, 代码如下所示: void swap(int a,int b) { a = a^b; b = a^b; a = a^b; }  原因是:异或运算是它本身的逆运算,故对于两个数或是布尔变量有如下性质: (a XOR b) XOR b = a 补充,异或运算的简单性质: 1. a ⊕ a = 0 2. a ⊕ b = b ⊕ a // 异或运算满足交换律 3. a ⊕ b ⊕ c = a ⊕ (b ⊕ c) = (a ⊕

异或运算实现加密解密

异或运算中,如果某个字符(或数值)x 与 一个数值m 进行异或运算得到y,则再用y 与 m 进行异或运算就可以还原为 x ,因此应用这个原理可以实现数据的加密解密功能. 异或运算在java中通常有两个比较常用的方法,一个是两个变量的互换(不借助第三个变量),一个便是数据的简单加密解密. 两个变量的互换 java运算中,如果要交换两变量的值,通常的做法就是借助第三个临时变量,然后完成操作. 如 public static void main(String[] args) { int[] arr =

网络误区:不用中间变量交换2个变量的value,最高效的是异或运算.

本文记录了不使用中间变量交换2个变量的value,很多的网络留言说是直接异或运算就可以了,而且效率很高,是真的吗? 关于这个问题,网络上面有很多的解释,3种方法,我这里给比较一下各自的优缺点,然后简单分析一下汇编代码,分析代码如下: #include <stdio.h> void swap1(int &a,int &b) { int temp = a; a = b; b = temp; } void swap2(int &a,int &b) { a += b;

异或运算

将a与b的对应位进行异或运算,同为0或者同为1时,对应位结果为0:否则为1.

【Luogu】P1681最大正方形2(异或运算,DP)

题目链接 不得不说attack是个天才.读入使用异或运算,令que[i][j]^=(i^j)&1,于是原题目变成了求que数组的最大相同值. 然而我还是不理解为啥,而且就算简化成这样我也不会做. ai,我太菜了. f[i][j]表示考虑到i,j为止的最大值.当que[i][j]=que[i-1][j]=que[i][j-1]=que[i-1][j-1]的时候,f[i][j]=min(f[i-1][j],min(f[i][j-1],f[i-1][j-1]))+1. #include<cstdi

FEC之异或运算应用

话说为啥FEC需要异或( ^/⊕ )操作呢? 异或:xor 异或运算规则: 0 xor 0 = 0 0 xor 1 = 1 1 xor 0 = 1 1 xor 1 = 0 异或运算特性: 1). a xor a = 0 2). a xor 0 = a 3). (a xor b) xor c = a xor (b xor c) 4). IF a xor b = c THEN a xor c = b    异或的运算特性有两点很好的应用 查找 case 1: 一个数组,除了其中一个元素,其他元素都为

使用异或运算实现中两个变量互换的方法

按位异或运算可以在不引入临时变量的情况下实现两个变量值得互换. int main() {     int a = 10;     int b = 12;     cout<<"a="<<a<<";"<<"b="<<b<<endl;     a = a^b;                                            //异或运算     b = a^