[十二省联考2019]异或粽子

前言

去年打酱油的时候,我还不会字典树= =

貌似我( equire{enclose}enclose{horizontalstrike}{O(n^2logn)})的分都没拿满?

题目

洛谷

讲解

异或?l~r的连续区间?

明显可以前缀和优化

接下来就变成了求前(k)大的点对异或值了

看题解得知,这种类型的问题可以这么解决:

先把所有的前缀和插入进一棵字典树中,注意要插入0

此字典树需要记录的信息有:

1.两个儿子(常规操作)

2.子树大小(记录这条路走下去可以最多选出多少个数)

然后我们可以将每一个前缀和的查询的最大值插进优先队列

每次取出最大的一个,累加答案,然后求出次大的值,放回优先队列...

循环做(k)次,就完事了

吗?

NO!由于(s_i oplus s_j=s_j oplus s_i),所以每个较大值会出现两次,我们要将(2k)个较大数累加起来,最后将答案除以二即可

时间复杂度为(O(nlog_2n))

注意开(long long)

代码

//12252024832524
#include <queue>
#include <cstdio>
#include <algorithm>
using namespace std; 

typedef long long LL;
const int MAXN = 500005;
const int MAXLOG = 32;
int n,k;
LL s[MAXN],ans;

LL Read()
{
	LL x = 0,f = 1;char c = getchar();
	while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
	return x * f;
}
void Put1(LL x)
{
	if(x > 9) Put1(x/10);
	putchar(x%10^48);
}
void Put(LL x,char c = -1)
{
	if(x < 0) putchar('-'),x = -x;
	Put1(x);
	if(c >= 0) putchar(c);
}
template <typename T>T Max(T x,T y){return x > y ? x : y;}
template <typename T>T Min(T x,T y){return x < y ? x : y;}
template <typename T>T Abs(T x){return x < 0 ? -x : x;}

struct Node
{
	int ID,rk;
	LL val;
	Node(){}
	Node(int ID1,int rk1,LL val1){
		ID = ID1;
		rk = rk1;
		val = val1;
	}
	bool operator < (const Node &px) const{
		return val < px.val;
	}
};
priority_queue<Node> q;

int tot;
struct node
{
	int ch[2],siz;
}t[MAXN * MAXLOG];
void ins(LL x)
{
	int now = 0;
	for(int i = MAXLOG - 1;i >= 0;-- i)
	{
		bool ID = x >> i & 1;
		if(!t[now].ch[ID]) t[now].ch[ID] = ++tot;
		now = t[now].ch[ID];
		t[now].siz++;
	}
}
LL query(int rk,LL w)
{
	int now = 0;
	LL ret = 0;
	for(int i = MAXLOG - 1;i >= 0;-- i)
	{
		bool ID = w >> i & 1,to = ID ^ 1;
		if(t[now].ch[to]) 
		{
			if(t[t[now].ch[to]].siz >= rk) now = t[now].ch[to],ret += 1ll << i;
			else rk -= t[t[now].ch[to]].siz,now = t[now].ch[ID];
		}
		else now = t[now].ch[ID];
	}
	return ret;
}

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	n = Read(); k = Read() << 1;
	for(int i = 1;i <= n;++ i) s[i] = Read() ^ s[i-1];
	for(int i = 0;i <= n;++ i) ins(s[i]);
	for(int i = 0;i <= n;++ i) q.push(Node(i,1,query(1,s[i])));
	while(k--)
	{
		Node g = q.top(); q.pop(); ans += g.val;
		if(g.rk < n) q.push(Node(g.ID,g.rk+1,query(g.rk+1,s[g.ID])));
	}
	Put(ans >> 1);
	return 0;
}
原文地址:https://www.cnblogs.com/PPLPPL/p/13392000.html