题目链接:

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

求前$k$大异或区间,可以发现$k$比较小,我们考虑找出每个区间。

为了快速得到一个区间的异或和,将原序列做前缀异或和。

对于每个点作为右端点时,我们维护出与他异或起来最大的左端点并将这组信息用结构体存起来插入堆中。

那么最大值就是堆顶那组(假设右端点为$r$),但考虑到次大值可能出自同一个右端点,所以在弹出堆顶后还需要将以$r$为右端点的次大值插入堆中。

那么如何求出以$r$为右端点的最大值和次大值?

我们对序列每个数为一个版本建可持久化$trie$树,那么最大值就是对于$[1,r]$版本(第一个版本插入的数为$a[0]$)求与一个数异或的最大值。

至于次大值,可以记录求最大值时的版本区间(设为$[l,r]$)及最大值所在序列(或版本)的位置(设为$mid$),在弹出最大值那组信息的同时插入$[l,mid-1]$和$[mid+1,r]$两个区间,分别对这两个区间求最大值即可。

因为需要求具体位置,所以在插入时需要在当前版本插入的一条链的叶子节点记录插入数在原数组的下标,当查询$[l,r]$时,返回$r$版本对应叶子节点记录的信息即可。因为每个版本只插入一个数,所以每个叶子结点记录的就是对应权值的最后一个位置,也就可以保证$r$版本对应叶子节点记录的信息一定在$[l,r]$之间。

那么要求出前$k$大,只需要每次取出堆顶然后将堆顶查询区间分为两部分再插入堆中,重复$k$次即可。

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
int cnt;
int root[500010];
int n,k;
ll ans;
struct miku
{
int ls,rs,size,id;
}tr[20000010];
ll a[500010],x;
void updata(int &rt,int pre,int dep,ll val,int num)
{
rt=++cnt;
tr[rt].size=tr[pre].size+1;
tr[rt].ls=tr[pre].ls;
tr[rt].rs=tr[pre].rs;
if(dep==0)
{
tr[rt].id=num;
return ;
}
if(val&(1<<(dep-1)))
{
updata(tr[rt].rs,tr[pre].rs,dep-1,val,num);
}
else
{
updata(tr[rt].ls,tr[pre].ls,dep-1,val,num);
}
}
int query(int x,int y,int dep,ll val)
{
if(dep==0)
{
return tr[y].id;
}
if(val&(1<<(dep-1)))
{
if(tr[tr[y].ls].size-tr[tr[x].ls].size>0)
{
return query(tr[x].ls,tr[y].ls,dep-1,val);
}
else
{
return query(tr[x].rs,tr[y].rs,dep-1,val);
}
}
else
{
if(tr[tr[y].rs].size-tr[tr[x].rs].size>0)
{
return query(tr[x].rs,tr[y].rs,dep-1,val);
}
else
{
return query(tr[x].ls,tr[y].ls,dep-1,val);
}
}
}
struct lty
{
int l,r,mid,rt;
ll val;
lty(){}
lty(int L,int R,int RT)
{
l=L,r=R,rt=RT;
mid=query(root[l-1],root[r],32,a[rt]);
val=a[rt]^a[mid-1];
}
bool operator <(lty a)const
{
return val<a.val;
}
};
priority_queue<lty>q;
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%lld",&x);
a[i]=a[i-1]^x;
}
for(int i=1;i<=n;i++)
{
updata(root[i],root[i-1],32,a[i-1],i);
}
for(int i=1;i<=n;i++)
{
q.push(lty(1,i,i));
}
while(k--&&!q.empty())
{
lty now=q.top();
q.pop();
ans+=now.val;
if(now.mid>now.l)
{
q.push(lty(now.l,now.mid-1,now.rt));
}
if(now.mid<now.r)
{
q.push(lty(now.mid+1,now.r,now.rt));
}
}
printf("%lld",ans);
}

还有一种解决方法是记录以$r$为右端点的区间已经取了前$k$大,每次取出堆顶将堆顶记录的$k$加一,查询第$k+1$大的异或区间再插入堆中。这样每组只需要存三个信息相对于上一种方法常数较小。

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
int cnt;
int root[500010];
int n,k;
ll ans;
struct miku
{
int ls,rs,size;
}tr[20000010];
ll a[500010],x;
void updata(int &rt,int pre,int dep,ll val)
{
rt=++cnt;
tr[rt].size=tr[pre].size+1;
tr[rt].ls=tr[pre].ls;
tr[rt].rs=tr[pre].rs;
if(dep==0)
{
return ;
}
if(val&(1<<(dep-1)))
{
updata(tr[rt].rs,tr[pre].rs,dep-1,val);
}
else
{
updata(tr[rt].ls,tr[pre].ls,dep-1,val);
}
}
ll query(int rt,int dep,ll val,int k)
{
if(dep==0)
{
return 0ll;
}
if(val&(1<<(dep-1)))
{
int res=tr[tr[rt].ls].size;
if(res>=k)
{
return query(tr[rt].ls,dep-1,val,k)+(1ll<<(dep-1));
}
else
{
return query(tr[rt].rs,dep-1,val,k-res);
}
}
else
{
int res=tr[tr[rt].rs].size;
if(res>=k)
{
return query(tr[rt].rs,dep-1,val,k)+(1ll<<(dep-1));
}
else
{
return query(tr[rt].ls,dep-1,val,k-res);
}
}
}
struct lty
{
int k,rt;
ll val;
lty(){}
lty(int K,int RT)
{
k=K,rt=RT;
val=query(root[rt],32,a[rt],k);
}
bool operator <(lty a)const
{
return val<a.val;
}
};
priority_queue<lty>q;
int main()
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%lld",&x);
a[i]=a[i-1]^x;
}
for(int i=1;i<=n;i++)
{
updata(root[i],root[i-1],32,a[i-1]);
}
for(int i=1;i<=n;i++)
{
q.push(lty(1,i));
}
while(k--&&!q.empty())
{
lty now=q.top();
q.pop();
ans+=now.val;
q.push(lty(now.k+1,now.rt));
}
printf("%lld",ans);
}

[十二省联考2019]异或粽子——可持久化trie树+堆的更多相关文章

  1. 洛谷.5283.[十二省联考2019]异或粽子(可持久化Trie 堆)

    LOJ 洛谷 考场上都拍上了,8:50才发现我读错了题=-= 两天都读错题...醉惹... \(Solution1\) 先求一遍前缀异或和. 假设左端点是\(i\),那么我们要在\([i,n]\)中找 ...

  2. [十二省联考2019] 异或粽子 - 可持久化Trie,堆

    求 \(n\) 元数列的 \(k\) 个不同的子区间使得各个子区间异或和之和最大. Solution (差点又看错题了) 做个前缀和,于是转化成求序列异或和最大的 \(k\) 个数对 建一棵可持久化 ...

  3. P5283 [十二省联考2019]异或粽子 可持久化01Trie+线段树

    $ \color{#0066ff}{ 题目描述 }$ 小粽是一个喜欢吃粽子的好孩子.今天她在家里自己做起了粽子. 小粽面前有 \(n\) 种互不相同的粽子馅儿,小粽将它们摆放为了一排,并从左至右编号为 ...

  4. 【BZOJ5495】[十二省联考2019]异或粽子(主席树,贪心)

    [BZOJ5495][十二省联考2019]异或粽子(主席树,贪心) 题面 BZOJ 洛谷 题解 这不是送分题吗... 转异或前缀和,构建可持久化\(Trie\). 然后拿一个堆维护每次的最大值,每次如 ...

  5. [十二省联考2019]异或粽子 01trie

    [十二省联考2019]异或粽子 01trie 链接 luogu 思路 首先求前k大的(xo[i]^xo[j])(i<j). 考场上只想到01trie,不怎么会写可持久,就写了n个01trie,和 ...

  6. 【简】题解 P5283 [十二省联考2019]异或粽子

    传送门:P5283 [十二省联考2019]异或粽子 题目大意: 给一个长度为n的数列,找到异或和为前k大的区间,并求出这些区间的异或和的代数和. QWQ: 考试时想到了前缀异或 想到了对每个数按二进制 ...

  7. 【洛谷5283】[十二省联考2019] 异或粽子(可持久化Trie树+堆)

    点此看题面 大致题意: 求前\(k\)大的区间异或和之和. 可持久化\(Trie\)树 之前做过一些可持久化\(Trie\)树题,结果说到底还是主席树. 终于,碰到一道真·可持久化\(Trie\)树的 ...

  8. Luogu P5283 / LOJ3048 【[十二省联考2019]异或粽子】

    联考Day1T1...一个考场上蠢了只想到\(O(n^2)\)复杂度的数据结构题 题目大意: 求前\(k\)大区间异或和的和 题目思路: 真的就是个sb数据结构题,可持久化01Trie能过(开O2). ...

  9. [十二省联考2019]异或粽子(堆+可持久化Trie)

    前置芝士:可持久化Trie & 堆 类似于超级钢琴,我们用堆维护一个四元组\((st, l, r, pos)\)表示以\(st\)为起点,终点在\([l, r]\)内,里面的最大值的位置为\( ...

随机推荐

  1. asp.net/wingtip/UI和导航

    ASP.NET Web窗体可以让web应用创建动态内容.静态网页的知识和HTML.CSS一模一样,区别在于ASP.NET网页包括了ASP.NET可以识别并处理的服务器端的内容.对于静态页面(.html ...

  2. MongoDB的存储结构及对空间使用率的影响

    MongoDB的存储结构及对空间使用率的影响 使用MongoDB一段时间的同学肯定会发现,MongoDB往往会占用比实际数据大小多不少空间的问题.如果利用db.stats()命令去查看,会发现Mong ...

  3. axios中的this指向问题

    最近在使用vue过程中,使用axios进行接口请求,确发现取不到值,返回为undefined. show (item) { let searchText = item.keyword console. ...

  4. Jmeter设置代理,抓包之app请求

    步骤: 1. Jmeter选择测试计划,添加线程组,添加http请求,添加监听器-察看结果树 2. 添加http代理服务器,右键添加非测试元件-添加http代理服务器 3. 端口改为8889,目标控制 ...

  5. (二)版本控制管理器之CVS(上)

    在前一篇<(一)版本控制管理器之发展史>的介绍中,有提到古典时期的CVS,那什么是CVS?CVS特点是什么?怎么个用法?等一系列的问题,虽然这个版本控制管理器早已过时,但大家了解下也不妨, ...

  6. CAP理论和Base理论

    CAP理论 Consistency(一致性), 数据一致更新,所有数据变动都是同步的 Availability(可用性), 好的响应性能 Partition tolerance(分区容错性) 可靠性, ...

  7. 解决Linux系统下Mysql数据库中文显示成问号的问题

    当我们将开发好的javaWEB项目部署到linux系统上,操作数据库的时候,会出现中文乱码问题,比如做插入操作,发现添加到数据库的数据中文出现论码,下面就将解决linux下mysql中文乱码问题! 打 ...

  8. c/c++ 继承与多态 容器与继承2

    c/c++ 继承与多态 容器与继承1说明了容器里使用继承关系的方法,这里再弄一个练习,巩固一下. 做一个类Basket,它有个multiset成员,key是智能指针std::shared_ptr< ...

  9. c/c++ 多线程 等待一次性事件 packaged_task用法

    多线程 等待一次性事件 packaged_task用法 背景:不是很明白,不知道为了解决什么业务场景,感觉std::asynck可以优雅的搞定一切,一次等待性事件,为什么还有个packaged_tas ...

  10. Win10 - MySQL 5.7 密码重置

    Win10 - MySQL 5.7 密码重置 所有行为均发生在系统管理员权限的 Cmd 或 Powershell 下 注意! 本行为会导致数据库重置 # 重新安装 mysql 服务 mysqld -- ...