zoukankan      html  css  js  c++  java
  • BZOJ5495 [2019省队联测]异或粽子

    题意:

    给定一个序列,问最大的k段连续异或和的代数和。

    知识点:

    可持久化Trie,堆

    解法:

    首先异或的一个性质可以把连续子串转化成前缀和的形式维护。

    然后看到异或代数和最大,可以想到可持久化Trie。

    但是维护的方法又有两种。

    第一种也是我一开始想到的,把n个值最大的放到堆中,每次从堆中取出一个元素,更新答案;然后找出这个元素唯一对应的下一个值(暴力跳trie,最多不超过64次)。但是太难了。

    第二种就是超级钢琴的做法,在l到r中找到最大的答案为pos点,然后放入l到pos-1和pos-1到r继续更新答案即可。

    备注:

    这种超级钢琴的做法很值得学习。注意这道题堆里面要维护的是l,r,pos,val,id,id不可以省。

    代码:

    #include<cstdio>
    #include<cstring>
    #include<queue>
    using namespace std;
    
    typedef long long ll;
    const int maxn=500010;
    int n,m,tot,bit[35],rt[maxn];
    ll ans,sum[maxn];
    struct trie
    {
    	int ch[2],tag,id;
    }a[maxn*40];
    struct data
    {
    	int l,r;
    	ll val;
    	int pos,id;
    	bool operator <(const data &b)const
    	{
    		return val<b.val;
    	}
    };
    priority_queue<data>q;
    
    ll read()
    {
    	ll x=0;
    	char c=getchar();
    	while (c<48||c>57)
    		c=getchar();
    	while (c>=48&&c<=57)
    		x=(x<<1)+(x<<3)+(c^48),c=getchar();
    	return x;
    }
    
    void div(ll x)
    {
    	int i;
    	for (i=31;i>=0;i--)
    	{
    		bit[i]=(x&1);
    		x>>=1;
    	}
    }
    
    void insert(int &x,int y,int id)
    {
    	x=(++tot);
    	a[x].tag=id;
    	int i,u=x;
    	for (i=0;i<=31;i++)
    	{
    		a[u].ch[bit[i]]=(++tot);
    		a[tot].tag=id;
    		if (y)
    			a[u].ch[bit[i]^1]=a[y].ch[bit[i]^1];
    		u=a[u].ch[bit[i]];
    		if (y)
    			y=a[y].ch[bit[i]];
    	}
    	a[u].id=id;
    }
    
    ll query(int l,int r,int &pos)
    {
    	pos=0;
    	ll res=0;
    	int i,u=rt[r];
    	for (i=0;i<=31;i++)
    	{
    		if (a[u].ch[bit[i]^1]&&a[a[u].ch[bit[i]^1]].tag>=l)
    		{
    			res|=(1ll<<(31-i));
    			u=a[u].ch[bit[i]^1];
    		}
    		else
    			u=a[u].ch[bit[i]];
    	}
    	pos=a[u].id;
    	return res;
    }
    
    int main()
    {
    	int i,u;
    	ll x,v;
    	n=read(),m=read();
    	sum[0]=0;
    	insert(rt[0],0,0);
    	for (i=1;i<=n;i++)
    	{
    		x=read();
    		sum[i]=sum[i-1]^x;
    		div(sum[i]);
    		v=query(0,i-1,u);
    		q.push((data){0,i-1,v,u,i});
    		insert(rt[i],rt[i-1],i);
    	}
    	data c;
    	while (m--)
    	{
    		c=q.top();
    		q.pop();
    		ans+=c.val;
    		div(sum[c.id]);
    		if (c.l<c.pos)
    		{
    			v=query(c.l,c.pos-1,u);
    			q.push((data){c.l,c.pos-1,v,u,c.id});
    		}
    		if (c.pos<c.r)
    		{
    			v=query(c.pos+1,c.r,u);
    			q.push((data){c.pos+1,c.r,v,u,c.id});
    		}
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    ios开发系列-准备工作
    tests
    腾讯DBA官方博客开通了,欢迎交流
    腾讯DBA官方博客开通了
    [HNOI2008]水平可见直线
    BZOJ-4518 征途
    CDQ分治与整体二分
    HYSBZ-1176 Mokia
    二逼平衡树
    可持久化数组
  • 原文地址:https://www.cnblogs.com/Ronald-MOK1426/p/12298846.html
Copyright © 2011-2022 走看看