题目链接:
求前$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树+堆的更多相关文章
-
洛谷.5283.[十二省联考2019]异或粽子(可持久化Trie 堆)
LOJ 洛谷 考场上都拍上了,8:50才发现我读错了题=-= 两天都读错题...醉惹... \(Solution1\) 先求一遍前缀异或和. 假设左端点是\(i\),那么我们要在\([i,n]\)中找 ...
-
[十二省联考2019] 异或粽子 - 可持久化Trie,堆
求 \(n\) 元数列的 \(k\) 个不同的子区间使得各个子区间异或和之和最大. Solution (差点又看错题了) 做个前缀和,于是转化成求序列异或和最大的 \(k\) 个数对 建一棵可持久化 ...
-
P5283 [十二省联考2019]异或粽子 可持久化01Trie+线段树
$ \color{#0066ff}{ 题目描述 }$ 小粽是一个喜欢吃粽子的好孩子.今天她在家里自己做起了粽子. 小粽面前有 \(n\) 种互不相同的粽子馅儿,小粽将它们摆放为了一排,并从左至右编号为 ...
-
【BZOJ5495】[十二省联考2019]异或粽子(主席树,贪心)
[BZOJ5495][十二省联考2019]异或粽子(主席树,贪心) 题面 BZOJ 洛谷 题解 这不是送分题吗... 转异或前缀和,构建可持久化\(Trie\). 然后拿一个堆维护每次的最大值,每次如 ...
-
[十二省联考2019]异或粽子 01trie
[十二省联考2019]异或粽子 01trie 链接 luogu 思路 首先求前k大的(xo[i]^xo[j])(i<j). 考场上只想到01trie,不怎么会写可持久,就写了n个01trie,和 ...
-
【简】题解 P5283 [十二省联考2019]异或粽子
传送门:P5283 [十二省联考2019]异或粽子 题目大意: 给一个长度为n的数列,找到异或和为前k大的区间,并求出这些区间的异或和的代数和. QWQ: 考试时想到了前缀异或 想到了对每个数按二进制 ...
-
【洛谷5283】[十二省联考2019] 异或粽子(可持久化Trie树+堆)
点此看题面 大致题意: 求前\(k\)大的区间异或和之和. 可持久化\(Trie\)树 之前做过一些可持久化\(Trie\)树题,结果说到底还是主席树. 终于,碰到一道真·可持久化\(Trie\)树的 ...
-
Luogu P5283 / LOJ3048 【[十二省联考2019]异或粽子】
联考Day1T1...一个考场上蠢了只想到\(O(n^2)\)复杂度的数据结构题 题目大意: 求前\(k\)大区间异或和的和 题目思路: 真的就是个sb数据结构题,可持久化01Trie能过(开O2). ...
-
[十二省联考2019]异或粽子(堆+可持久化Trie)
前置芝士:可持久化Trie & 堆 类似于超级钢琴,我们用堆维护一个四元组\((st, l, r, pos)\)表示以\(st\)为起点,终点在\([l, r]\)内,里面的最大值的位置为\( ...
随机推荐
-
bootstrap1
让bootstarp3 支持ie的兼容模式: 支持浏览器的响应式布局: 是指网页既可以用在pc上,也可以用在手机上, 而且不需要修改源文件. bootstrap包括: css文件, 只需要加载: cs ...
-
Knockout.js随手记(4)
动态绑定下拉列表 在<select> data-bind的options选项如果绑定到ko.observableArray(),就可以动态新增选项效果,也就是可以利用其完成常见的级联效果的 ...
-
C++模板元编程 - 挖新坑的时候探索到了模板元编程的新玩法
C++真是一门*的语言,虽然糖没有C#那么多,但是你想要怎么写,想要实现什么,想要用某种编程范式或者语言特性,它都会提供. 开大数运算类的新坑的时候(又是坑),无意中需要解决一个需求:大数类需要分别 ...
-
PHP高级——抽象类与接口的区别(转)
在学习PHP面向对象时,都会在抽象类与接口上迷惑,作用差不多为什么还那么容易混淆,何不留一去一?但是事实上两者的区别还是很大的,如果能够很好地运用PHP的两个方法,面向对象的程序设计将会更加合理.清晰 ...
-
网络统计学与web前端开发基础技术
网络统计学与web前端开发基础技术 学习web前端开发基础技术(网页设计)需要了解:HTML.CSS.JavaScript三种语言.下面我们就来了解一下这三门技术在网页设计中的用途: HTML是网页内 ...
-
2014ACM/ICPC亚洲区西安站 F题 color (组合数学,容斥原理)
题目链接:传送门 题意: n个格子排成一行.我们有m种颜色.能够给这些格子涂色,保证相邻的格子的颜色不同 问,最后恰好使用了k种颜色的方案数. 分析: 看完题目描写叙述之后立刻想到了一个公式 :C(m ...
-
mysql基础之存储引擎
原文:mysql基础之存储引擎 数据库对同样的数据,有着不同的存储方式和管理方式,在mysql中,称为存储引擎 常用的表的引擎 Myisam ,批量插入速度快, 不支持事务,锁表 Innodb, 批量 ...
-
log4j2
转载自 Blog of 天外的星星: http://www.cnblogs.com/leo-lsw/p/log4j2tutorial.html Log4j 2的好处就不和大家说了,如果你搜了2,说明你 ...
-
The Singularity is Near---预测人工智能,科技走向的神书---奇点临近
比尔盖茨评价本文作者: 雷·库兹韦尔是我所知道的预测人工智能未来最权威的人.他的这本耐人寻味的书预测未来信息技术得到空前发展,将促使人类超越自身的生物极限--以我们无法想象的方式超越我们的生命. 中文 ...
-
c#解决TCP“粘包”问题
一:TCP粘包产生的原理 1,TCP粘包是指发送方发送的若干包数据到接收方接收时粘成一包,从接收缓冲区看,后一包数据的头紧接着前一包数据的尾.出现粘包现象的原因是多方面的,它既可能由发送方造成,也可能 ...