zoukankan      html  css  js  c++  java
  • 【洛谷P5283】异或粽子【Trie】【堆】

    题目大意:

    题目链接:https://www.luogu.org/problemnew/show/P5283
    给出一个序列,找到mm个区间[li,ri][l_i,r_i]使得这些区间的异或和最大。


    思路 :

    先做一遍前缀异或,这样问题就被转换成找mml,rl,r使得l xor rsum l xor r尽量大。
    注意到a[l] xor a[r]=a[r] xor a[l]a[l] xor a[r]=a[r] xor a[l],所以如果选了l,rl,r,那么也会选一遍r,lr,l。这样的话我们可以将询问次数×2 imes 2,这样每连续的两组查询就是一组相同的(l,r)(r,l)(l,r)(r,l)。最终答案除以2就行了。
    我们维护一个堆,将每一个ii所对应的a[i] xor a[j]a[i] xor a[j]最大的jj扔到堆里面,每次询问取堆顶,将下一大的a[i] xor a[j]a[i] xor a[j]扔到堆中。
    对于xxyy使得a[x] xor a[y]a[x] xor a[y]为第kk大显然是可以用TrieTrie维护的。每次利用权值来判断往子树的左右。
    这样就可以不使用可持久化TrieTrie来完成这道题了。时间复杂度O(nlogn)O(nlog n)


    代码:

    #include <queue>
    #include <cstdio>
    #include <string>
    #include <iostream>
    #define mp make_pair
    using namespace std;
    typedef long long ll;
    
    const int N=500010,LG=35;
    int n,m,tot=1,trie[N*LG][2],cnt[N],size[N*LG];
    ll a[N],ans;
    priority_queue<pair<ll,int> > q;
    
    ll read()
    {
        ll d=0;
        char ch=getchar();
        while (!isdigit(ch)) ch=getchar();
        while (isdigit(ch))
            d=(d<<3)+(d<<1)+(ll)ch-48LL,ch=getchar();
        return d;
    }
    
    void insert(ll x)
    {
        int p=1;
        for (int i=LG;i>=0;i--)
        {
            int id=(x>>(ll)i)&1;
            if (!trie[p][id]) trie[p][id]=++tot;
            p=trie[p][id];
            size[p]++;
        }
    }
    
    ll find(ll x,int k)
    {
        int p=1; 
        ll ans=0;
        for (int i=LG;i>=0;i--)
        {
            int id=(x>>(ll)i)&1;
            if (trie[p][id^1]&&size[trie[p][id^1]]>=k)
            {
                ans=(ans<<1)|1;
                p=trie[p][id^1];
            }
            else if (trie[p][id])
            {
                k-=size[trie[p][id^1]];
             	ans<<=1;
             	p=trie[p][id];
            }
        }
        return ans;
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        insert(0); cnt[0]=1;
        for (int i=1;i<=n;i++)
        {
            a[i]=read();
            a[i]^=a[i-1];
            insert(a[i]);
            cnt[i]=1;
        }
        for (int i=0;i<=n;i++)
            q.push(mp(find(a[i],1),i));
        m*=2;
        while (m--)
        {
        	if (!q.size()) break;
            ans+=q.top().first;
            int i=q.top().second;
            q.pop();
            cnt[i]++;
            if (cnt[i]<=n+1)
                q.push(mp(find(a[i],cnt[i]),i));
        }
        cout<<ans/2LL;
        return 0;
    }
    
  • 相关阅读:
    js中disabled属性
    ajax 失焦点局部刷新 判断是否存在
    java 常见异常总结
    struts2+spring+hibernate 分别是做什么?
    武汉·骑行·摄影
    [转]基于粒子滤波的物体跟踪
    [转]Chrome插件:下载YouTube视频
    windows下GSL的配置
    图像处理和计算机视觉中的经典论文
    终于在我电脑上跑通ZK大神给的TLD代码了
  • 原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998130.html
Copyright © 2011-2022 走看看