题目链接

题目:

中文描述不清,不如直接看题面

(1≤n,q≤105,0≤ai<230,1≤L<R<230,1≤K≤n)(1 \le n,q \le 10^5,0 \le a_i <2^{30},1 \le L<R<2^{30},1 \le K \le n)(1≤n,q≤105,0≤ai​<230,1≤L<R<230,1≤K≤n)

题解:

如果对01trie的基本操作不是很熟悉,可以参考这里
这种异或的操作显然可以在01trie上实现。先将序列aaa中所有的元素插入到01trie中。
首先考虑单个f(a,S,K)f(a,S,K)f(a,S,K)怎么实现。其中第一个问题是如何实现将序列aaa中所有的元素异或上SSS?如果SSS的二进制表示从高到底第iii位为1,那么就将01trie中第iii层结点的左右子树互换,如果第iii位为0,就不操作。第二个问题是如何找第KKK小?因为01trie本质上就是一棵权值线段树,所以可以照搬权值线段树找第KKK小的树上二分的方法来实现,即每个结点uuu维护一个信息szusz_uszu​,表示以uuu为根节点的子树中有多少个叶子(即结点uuu管着多少个aia_iai​),如果左子结点的szszsz大于等于KKK,那么第KKK小就在左子树的叶子结点中,往左走,否则往右走。
然后考虑一个这个问题的简化版,如果没有LLL和RRR的限制,即求min⁡0≤S<230f(a,S,K)\min \limits_{0 \le S <2^{30}}{f(a,S,K)}0≤S<230min​f(a,S,K)。可以发现这个问题是不能从高到低位贪心的,因为有后效性,但可以用dpdpdp来解。令kthu,ikth_{u,i}kthu,i​表示从结点uuu往下可以得到的最小的f(a,S,i)f(a,S,i)f(a,S,i),然后转移方程就是:
(假设结点uuu处于第ddd层,即现在要决策的是SSS的第ddd位)
(1)假设SSS的该位为0,那么可得
ans1={kthlsonu,ilsonu∃&&szlsonu≤i230−d+kthrsonu,i−szlsonuelseans1=\begin{cases} kth_{lson_u,i} \quad\quad\quad lson_u \exist \ \&\&sz_{lson_u} \le i \\ 2^{30-d}+kth_{rson_u,i-sz_{lson_u}} \quad else \end{cases} ans1={kthlsonu​,i​lsonu​∃ &&szlsonu​​≤i230−d+kthrsonu​,i−szlsonu​​​else​
(2)假设SSS的该位为1,那么可得

ans2={kthrsonu,irsonu∃&&szrsonu≤i230−d+kthlsonu,i−szrsonuelseans2=\begin{cases} kth_{rson_u,i} \quad\quad\quad rson_u \exist \ \&\&sz_{rson_u} \le i \\ 2^{30-d}+kth_{lson_u,i-sz_{rson_u}} \quad else \end{cases} ans2={kthrsonu​,i​rsonu​∃ &&szrsonu​​≤i230−d+kthlsonu​,i−szrsonu​​​else​
那么
kthu,i=min⁡(ans1,ans2)kth_{u,i}=\min(ans1,ans2)kthu,i​=min(ans1,ans2)
这样上述就可以做到O(nlog值域)O(nlog_{\text 值域})O(nlog值域​)预处理,O(1)O(1)O(1)查询。关于kthkthkth数组的空间大小,每个叶子结点会对从根到该叶子结点的路径上所有的点的第二维产生一个贡献,一共有nnn个叶子结点,所以kthkthkth数组的空间是O(nlog值域)O(nlog_{值域})O(nlog值域​)的。
回到本题,在上面那个子问题的基础上加上了L,RL,RL,R的限制。在从高位到低位决策SSS的过程中,一开始L,RL,RL,R的对应位一定是一样的(或者没有这个阶段),在这个阶段我们只能把SSS的该位确定为与L,RL,RL,R的该位一样,没有发生决策,只需要根据按照找第KKK小的逻辑走进对应的子树即可;然后到达某个位时,LLL的该位为0,RRR的该位为1,这时候我们就需要决策了:
(假设当前决策的位为第ddd位)
(1)假设将SSS的该位确定为0,那么接下来的上下界限制就变成了[lowL,d,231−d)[low_{L,d},2^{31-d})[lowL,d​,231−d)(其中lowL,dlow_{L,d}lowL,d​表示从LLL的第ddd位作为最高位和其他的低位构成的数),相当于只有下界了,接下来的决策过程就要发生变化:如果LLL该位为1,那么SSS的该位只能确定为1;如果LLL该位为0,那么如果SSS的该位取0,即贴着下界,就往对应的子树走接着进行同样的决策过程(因为之后还是只有下界的状态),如果SSS该位取1,那么接下来的决策过程就变成了无界了,那么就可以不用往下走,直接用上面的子问题中处理出的kthkthkth数组得到结果,比较两种决策结果,就能得到最优的决策。因为我们每次只会往一边走,所以这一部分的复杂度是O(log值域)O(log_{\text{值域}})O(log值域​)的。
(2)假设将SSS的该位确定为1,跟(1)类似,变成了只有上界。

按照上述过程,我们就可以得到询问结果了。

复杂度:O((n+q)log值域)O((n+q)log_{值域})O((n+q)log值域​)

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<string>
#include<bitset>
#include<sstream>
#include<ctime>
//#include<chrono>
//#include<random>
#include<unordered_map>
using namespace std;#define ll long long
#define ls o<<1
#define rs o<<1|1
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define sz(x) (int)(x).size()
#define all(x) (x).begin(),(x).end()
const double pi=acos(-1.0);
const double eps=1e-6;
const int mod=1e9+7;
const int INF=0x3f3f3f3f;
const int maxn=1e5+5;
ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;
}
struct Trie_01{int ch[maxn*32][2],sz[maxn*32],val[maxn*32];vector<int>kth[maxn*32];int tot;void init(){tot=0;ch[0][0]=ch[0][1]=0;}int newnode(){++tot;ch[tot][0]=ch[tot][1]=0;kth[tot].clear();val[tot]=0;return tot;}void ins(int x){int now=0;for(int i=29;i>=0;i--){int d=(x>>i)&1;if(!ch[now][d]){ch[now][d]=newnode();}now=ch[now][d];val[now]++;}}void dfs(int u){if(!ch[u][0]&&!ch[u][1]){sz[u]=val[u];return;}if(ch[u][0]){dfs(ch[u][0]);sz[u]+=sz[ch[u][0]];}if(ch[u][1]){dfs(ch[u][1]);sz[u]+=sz[ch[u][1]];}}void dfs2(int u,int d){if(!ch[u][0]&&!ch[u][1]){kth[u].resize(val[u]+1);for(int i=1;i<=val[u];i++){kth[u][i]=0;}return;}if(ch[u][0]){dfs2(ch[u][0],d-1);}if(ch[u][1]){dfs2(ch[u][1],d-1);}kth[u].resize(sz[u]+1);for(int i=1;i<=sz[u];i++){int ans1,ans2;//0int lnum=0;if(ch[u][0]){lnum=sz[ch[u][0]];}if(lnum>=i){ans1=kth[ch[u][0]][i];}else{ans1=(1<<d)+kth[ch[u][1]][i-lnum];}//1lnum=0;if(ch[u][1]){lnum=sz[ch[u][1]];}if(lnum>=i){ans2=kth[ch[u][1]][i];}else{ans2=(1<<d)+kth[ch[u][0]][i-lnum];}kth[u][i]=min(ans1,ans2);}}int dfs3(int u,int d,int l,int k){if(!ch[u][0]&&!ch[u][1])return 0;int bit=(l>>d)&1;if(bit==1){int lnum=0;if(ch[u][1]){lnum=sz[ch[u][1]];}if(lnum>=k){return dfs3(ch[u][1],d-1,l,k);}else{return (1<<d)+dfs3(ch[u][0],d-1,l,k-lnum);}}   else{int ans1,ans2;int lnum=0;//0if(ch[u][0]){lnum=sz[ch[u][0]];}if(lnum>=k){ans1=dfs3(ch[u][0],d-1,l,k);}else{ans1=(1<<d)+dfs3(ch[u][1],d-1,l,k-lnum);}//1lnum=0;if(ch[u][1]){lnum=sz[ch[u][1]];}if(lnum>=k){ans2=kth[ch[u][1]][k];}else{ans2=(1<<d)+kth[ch[u][0]][k-lnum];}return min(ans1,ans2);}}int dfs4(int u,int d,int r,int k){if(!ch[u][0]&&!ch[u][1])return 0;int bit=(r>>d)&1;if(bit==0){int lnum=0;if(ch[u][0]){lnum=sz[ch[u][0]];}if(lnum>=k){return dfs4(ch[u][0],d-1,r,k);}else{return (1<<d)+dfs4(ch[u][1],d-1,r,k-lnum);}} else{int ans1,ans2;int lnum=0;//0if(ch[u][0]){lnum=sz[ch[u][0]];}if(lnum>=k){ans1=kth[ch[u][0]][k];}else{ans1=(1<<d)+kth[ch[u][1]][k-lnum];}//1lnum=0;if(ch[u][1]){lnum=sz[ch[u][1]];}if(lnum>=k){ans2=dfs4(ch[u][1],d-1,r,k);}else{ans2=(1<<d)+dfs4(ch[u][0],d-1,r,k-lnum);}return min(ans1,ans2);}}int solve(int u,int d,int l,int r,int k){if(!ch[u][0]&&!ch[u][1])return 0;int lbit=(l>>d)&1,rbit=(r>>d)&1;if(lbit==rbit){int lnum=0;int zero=lbit;if(ch[u][zero]){lnum=sz[ch[u][zero]];}if(lnum>=k){return solve(ch[u][zero],d-1,l,r,k);}else{return (1<<d)+solve(ch[u][zero^1],d-1,l,r,k-lnum);}}else{int ans1,ans2;//0int lnum=0;if(ch[u][0]){lnum=sz[ch[u][0]];}if(lnum>=k){ans1=dfs3(ch[u][0],d-1,l,k);}else{ans1=(1<<d)+dfs3(ch[u][1],d-1,l,k-lnum);}//1lnum=0;if(ch[u][1]){lnum=sz[ch[u][1]];}if(lnum>=k){ans2=dfs4(ch[u][1],d-1,r,k);}else{ans2=(1<<d)+dfs4(ch[u][0],d-1,r,k-lnum);}return min(ans1,ans2);}}
}tree;
int n,q;
int a[maxn];
int main(void){// freopen("in.txt","r",stdin);scanf("%d%d",&n,&q);tree.init();for(int i=1;i<=n;i++){scanf("%d",&a[i]);tree.ins(a[i]);}tree.dfs(0);tree.dfs2(0,29);int l,r,k;while(q--){scanf("%d%d%d",&l,&r,&k);printf("%d\n",tree.solve(0,29,l,r,k));}return 0;
}

2020ICPC济南K Kth Query相关推荐

  1. Fight against involution | 2020ICPC济南D

    Fight against involution from 2020ICPC济南 Time limit:1s Memory limit:256MB 题意: 在满足每个人成绩不减的前提下,找到最小的wi ...

  2. 二分图 ---- 树的二分图性质 2020icpc 济南 J Tree Constructer(构造)

    题目链接 题目大意: 就是给你一颗树,你要对树上点进行赋值,使得相邻两个有边的点的权值或是260−12^{60}-1260−1,任意两个没边的两个点的或不能为260−12^{60}-1260−1 n∈ ...

  3. 【HDU - 2665】Kth number(区间第K大,主席树,模板)

    题干: Give you a sequence and ask you the kth big number of a inteval. Input The first line is the num ...

  4. POJ 2104 K-th Number 主席树(区间第k大)

    题目链接: http://poj.org/problem?id=2104 K-th Number Time Limit: 20000MSMemory Limit: 65536K 问题描述 You ar ...

  5. POJ_2104 K-th Number 【主席树】

    一 题面 K-th Number 二 分析 第一个主席树的题,感触蛮多吧,几个关键点就是可持久化数据结构,这里的主席树其实就是保留了之前各个版本的权值线段树,然后利用权值线段树和历史版本可以进行相加减 ...

  6. COGS-930-找第k小的数-HNOI2012-主席树

    描述 静态区间第k小值 分析 改了一个主席树的模板, 改成了数组版. 感觉数组的要简洁好多. 主席树的讲解:http://hi.baidu.com/lov_zyf/item/87b578342e73f ...

  7. 【HDU - 4217 】Data Structure? (线段树求第k小数)

    题干: Data structure is one of the basic skills for Computer Science students, which is a particular w ...

  8. K-th Number

    题目链接:http://poj.org/problem?id=2104 K-th Number Time Limit: 20000MS   Memory Limit: 65536K Total Sub ...

  9. 划分树基础 —— HDU 2665 Kth number

    对应 HDU 题目 :点击打开链接 Kth number Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K ...

最新文章

  1. 新浪宣布2010年第四季度业绩 盘后跌4%
  2. 未来计算机的缺陷,新技术将计算机芯片缺陷变为优势
  3. Bluetooth Obex
  4. [WPF疑难]如何禁用WPF窗口的系统菜单(SystemMenu)
  5. PyQt5笔记(04) -- 文本框的使用
  6. oracle9i 查询scn,在oracle10g 10.2.0.1上测试不完全恢复_recover database until scn
  7. 剑指offer面试题47. 礼物的最大价值(动态规划)
  8. EurekaClient启动报错:Invocation of destroy method failed on bean with name 'scopedTarget.eurekaClient'
  9. centos7安装lamp
  10. docker配置阿里云镜像加速器
  11. Untiy3D里用C#做出连线题目~
  12. 【老生谈算法】matlab实现LEACH 算法——LEACH 算法
  13. 解决在宝塔面板IIS服务器上部署svg/woff/woff2字体的问题
  14. 小武实习的debug日记2
  15. 编程语言介绍以及特点
  16. 微信小程序如何保存图片到本地?
  17. LeetCode 41-50题
  18. Unity技术手册 - 粒子发射和生命周期内速度子模块
  19. ATFX:人民银行1年期MLF降息10基点,USDCNH大涨
  20. android 百分号,Android XML百分比符号

热门文章

  1. 使用虹软SDK实现离线人脸注册,人脸登录(H5-JS前端,java后台)
  2. 类和对象(一)this指针详解
  3. 脑波震动(二):全身脑波震动
  4. 你应该知道的10件关于Java 6的事情
  5. 接口请求一般放在哪个生命周期中?
  6. MP4/MOV/3GP文件的“ftyp”
  7. java计算机毕业设计猫咪伤患会诊复查医疗平台源代码+数据库+系统+lw文档
  8. 机器学习比赛、项目之模板
  9. 毕业设计 stm32便携用电功率统计系统 -物联网 嵌入式 单片机
  10. 自己搭建php主机绑定域名,只需5步,教你用虚拟主机搭建出属于自己的网站