题目链接:

[十二省联考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. Selenium自动化-CSS元素定位

    接下来,开始讲解 CSS元素定位. CSS定位速度快,功能多,但是不能向上查找,比 xpath好用,是本人认为最好用的定位方式   大致用法总结: 具体使用仿上篇博客.http://www.cnblo ...

  2. 关于Skyline沿对象画boundingbox的探讨

    先来说说为什么要搞这个?项目中经常遇到的一个操作就是选定对象,以前都是通过Tint设置对象颜色来标识选定对象,但是随着图层中模型增多,模型色彩丰富,会出现选定色与对象颜色对比不明显的情况.因为看到Te ...

  3. OPC协议解析-关于OPC协议的几个问题

    1    什么是OPC协议? 为了便于自动化行业不同厂家的设备和应用程序能相互交换数据,定义了一个统一的接口函数,就是OPC协议规范.有了OPC就可以使用统一的方式去访问不同设备厂商的产品数据. OP ...

  4. android.database.sqlite.SQLiteException: no such column: aaa (code 1): , while compiling: DELETE FROM users WHERE user_name=aaa解决办法

    在写安卓登录注册时注销按钮闪退发现: 这是因为此处错误: 因为用户名为字符串,不是整型,数据库查询要引号,少了引号查询不了,导致闪退 解决后成功运行 正确用法: 下次谨记,细节决定成败呀!

  5. docker与虚拟机有何不同

    docker与虚拟机有何不同 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化. 容器技术有 ...

  6. 关于MongoDB时间格式转换和时间段聚合统计的用法总结

    一 . 背景需求 在日常的业务需求中,我们往往会根据时间段来统计数据.例如,统计每小时的下单量:每天的库存变化,这类信息数据对运营管理很重要. 这类数据统计依赖于各个时间维度,年月日.时分秒都有可能. ...

  7. GO语言学习笔记(一)

    GO语言学习笔记 1.数组切片slice:可动态增长的数组 2.错误处理流程关键字:defer panic recover 3.变量的初始化:以下效果一样 `var a int = 10` `var ...

  8. Oracle导入、导出数据库dmp文件

    版本 1.实例数据完全导出 即导出指定实例下的所有数据 exp username/password@192.168.234.73/orcl file=d:/daochu/test.dmp full=y ...

  9. Vue学习之路1-集成环境安装

    1.前言 Vue 是一款友好的.多用途且高性能的javascript框架,与其它大型框架不同的是,Vue 被设计为可以自底向上逐层应用,它能够帮你创建可维护性和可测试性更强的代码库,Vue是渐进式的j ...

  10. Linux Collection:软件配置

    PAS Debian 9安装最新版Firefox( Firefox 58+/Quantum) Debian 9(Strech)的仓库包含的是firefox-esr(52)版本:需要安装最新版,有如下两 ...