先考虑p=qp=qp=q的情况,习惯先把求第kkk大变成求第k" role="presentation" style="position: relative;">kkk小。
那么我们逐个确定第kkk小的串每种数字包含了多少个。假设当前我们已经确定了x−1" role="presentation" style="position: relative;">x−1x−1x-1之前的数的个数,此时对于每个左端点iii,合法的右端点都是一个区间[li,ri]" role="presentation" style="position: relative;">[li,ri][li,ri][l_i,r_i]。现在考虑二分确定xxx的个数,我们把序列中为x" role="presentation" style="position: relative;">xxx的位置单独挑出来,这些位置把序列分成若干段,假如二分有midmidmid个xxx,那么对于每一段,合法的右端点又会有一个小于之后第mid" role="presentation" style="position: relative;">midmidmid的个xxx的位置的一个限制,然后再求合法区间个数。最后我们成功得到x" role="presentation" style="position: relative;">xxx的个数为numnumnum之后,每一段的合法右端点区间就要和其往后第numnumnum段求交。
以上这些区间求交操作就是对lilil_ichkmax或者对ririr_ichkmin,又因为li,rili,ril_i,r_i是随着iii单调不降的,我们可以用一棵线段树维护这些li,ri" role="presentation" style="position: relative;">li,rili,ril_i,r_i。
求出第ppp小之后,考虑如何推到第q" role="presentation" style="position: relative;">qqq小。注意到左端点固定时,随着右端点增大,串的大小也是增大的,于是我们可以找出每一个左端点第一个比ppp大的右端点并用一个堆来维护他们,每次弹出最小的[l,r]" role="presentation" style="position: relative;">[l,r][l,r][l,r]之后再把[l,r+1][l,r+1][l,r+1]加入堆。至于比较两个串的大小,可以用一棵主席树维护hash值,在上面二分找到第一个hash值不同的地方即可。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#define N 100010
#define ll long long
#define min(x,y) (x<y?x:y)
#define max(x,y) (x<y?y:x)
#define mid (l+r>>1)
using namespace std;
const int mod=1000000007,W=11003;
int n,m,a[N],z[N];
vector<int> t[N];
ll k0,k1,pw[N];
int read()
{int x=0,f=1;char ch=getchar();for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=-1;for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';return x*f;
}
struct tree2
{int rt[N],cnt,ch[N<<6][2],len[N<<6];ll w[N<<6];void update(int v){w[v]=(w[ch[v][0]]*pw[len[v]>>1]+w[ch[v][1]])%mod;}void build(int v,int p,int l,int r,int x){len[v]=r-l+1;if(l==r) {w[v]=w[p]+1;return;}if(x<=mid){ch[v][1]=ch[p][1];ch[v][0]=++cnt;build(cnt,ch[p][0],l,mid,x);}else{ch[v][0]=ch[p][0];ch[v][1]=++cnt;build(cnt,ch[p][1],mid+1,r,x);}update(v);}int compare(int pl,int pr,int ql,int qr,int l,int r){if(l==r) {if(w[pr]-w[pl]==w[qr]-w[ql]) return 0;return (w[pr]-w[pl]<w[qr]-w[ql]?-1:1);}if((w[ch[pr][0]]-w[ch[pl][0]]+mod)%mod==(w[ch[qr][0]]-w[ch[ql][0]]+mod)%mod)return compare(ch[pl][1],ch[pr][1],ch[ql][1],ch[qr][1],mid+1,r);elsereturn compare(ch[pl][0],ch[pr][0],ch[ql][0],ch[qr][0],l,mid);}
}T2;
struct node
{int l,r;bool operator <(node b){int tmp=T2.compare(T2.rt[l-1],T2.rt[r],T2.rt[b.l-1],T2.rt[b.r],1,m);if(tmp==0) return l>b.l;return tmp<0;}
}ans[N];
struct tree1
{int lmi[N<<2],lmx[N<<2],rmi[N<<2],rmx[N<<2];ll sl[N<<2],sr[N<<2],sx[N<<2];void update(int v){lmi[v]=min(lmi[v<<1],lmi[v<<1|1]);lmx[v]=max(lmx[v<<1],lmx[v<<1|1]);rmi[v]=min(rmi[v<<1],rmi[v<<1|1]);rmx[v]=max(rmx[v<<1],rmx[v<<1|1]);sl[v]=sl[v<<1]+sl[v<<1|1];sr[v]=sr[v<<1]+sr[v<<1|1];sx[v]=sx[v<<1]+sx[v<<1|1];}void pushdown(int v){if(lmi[v]>lmi[v<<1])sl[v<<1]=sx[v<<1]*lmi[v],lmi[v<<1]=lmx[v<<1]=lmi[v];if(lmi[v]>lmi[v<<1|1])sl[v<<1|1]=sx[v<<1|1]*lmi[v],lmi[v<<1|1]=lmx[v<<1|1]=lmi[v];if(rmx[v]<rmx[v<<1])sr[v<<1]=sx[v<<1]*rmi[v],rmi[v<<1]=rmx[v<<1]=rmx[v];if(rmx[v]<rmx[v<<1|1])sr[v<<1|1]=sx[v<<1|1]*rmi[v],rmi[v<<1|1]=rmx[v<<1|1]=rmx[v];}void build(int v,int l,int r){if(l==r){lmi[v]=lmx[v]=sl[v]=l;rmi[v]=rmx[v]=sr[v]=n;sx[v]=1;return ;}build(v<<1,l,mid);build(v<<1|1,mid+1,r);update(v);}ll calc(int v,int l,int r,int lx,int rx,int x){if(lx>rx||!sx[v]) return 0;if(l==lx&&r==rx){if(lmi[v]>x) return 0;if(rmx[v]<=x) return sr[v]-sl[v]+sx[v];if(lmx[v]<=x&&rmi[v]>x) {return sx[v]*(x+1)-sl[v];}}pushdown(v);if(rx<=mid) return calc(v<<1,l,mid,lx,rx,x);if(lx>mid) return calc(v<<1|1,mid+1,r,lx,rx,x);return calc(v<<1,l,mid,lx,mid,x)+calc(v<<1|1,mid+1,r,mid+1,rx,x);}void mdf(int v,int l,int r,int lx,int rx,int lc,int rc){if(lx>rx||!sx[v]) return ;if(l==lx&&r==rx){bool flag=1;if(lc>rmx[v]||rc<lmi[v]){sx[v]=sl[v]=sr[v]=0;return ;}else if(lc>=lmx[v]&&rc<=rmi[v])sl[v]=sx[v]*lc,sr[v]=sx[v]*rc;else if(lc<=lmi[v]&&rc>=lmx[v]&&rc<=rmi[v])sr[v]=sx[v]*rc;else if(lc>=lmx[v]&&lc<=rmi[v]&&rc>=rmx[v])sl[v]=sx[v]*lc;else if(lc<=lmi[v]&&rc>=rmx[v]){}else flag=0;if(flag){lmi[v]=max(lmi[v],lc);lmx[v]=max(lmx[v],lc);rmi[v]=min(rmi[v],rc);rmx[v]=min(rmx[v],rc);return ;}}pushdown(v);if(rx<=mid) mdf(v<<1,l,mid,lx,rx,lc,rc);else if(lx>mid) mdf(v<<1|1,mid+1,r,lx,rx,lc,rc);else mdf(v<<1,l,mid,lx,mid,lc,rc),mdf(v<<1|1,mid+1,r,mid+1,rx,lc,rc);update(v);}node find(int v,int l,int r,ll k){if(l==r) return (node){l,lmi[v]};pushdown(v);if(k<=sx[v<<1|1]) return find(v<<1|1,mid+1,r,k);else return find(v<<1,l,mid,k-sx[v<<1|1]);}
}T1;
ll check(int c,int x)
{ll re=0;int sz=t[c].size();for(int i=1;i<sz-x;i++)re+=T1.calc(1,1,n,t[c][i-1]+1,min(t[c][i],n),t[c][i+x]-1);re+=T1.calc(1,1,n,t[c][sz-x-1]+1,n,n);return re;
}
node solve0()
{for(int i=1;i<=m;i++){int sz=t[i].size(),L=0,R=sz-2;while(L<R){int Mid=(L+R>>1);if(check(i,Mid)<k0) L=Mid+1;else R=Mid;}if(L) k0-=check(i,L-1);for(int j=1;j<sz-L;j++)T1.mdf(1,1,n,t[i][j-1]+1,min(t[i][j],n),t[i][j+L-1],t[i][j+L]-1);   T1.mdf(1,1,n,t[i][sz-L-1]+1,n,n+1,n+1); }return T1.find(1,1,n,k0);
}struct gcmp
{bool operator() (node a,node b){return b<a;}
};
priority_queue<node,vector<node>,gcmp > Q;
void solve1()
{T2.rt[0]=0;for(int i=1;i<=n;i++)T2.rt[i]=++T2.cnt,T2.build(T2.cnt,T2.rt[i-1],1,m,a[i]);for(int i=1;i<=n;i++){int L=i,R=n;while(L<R){int Mid=(L+R>>1);node p=(node){i,Mid};if(p<ans[1]) L=Mid+1;else R=Mid;}node q=(node){i,L};if(!(q<ans[1])) Q.push(q);}for(int i=1;i<=k1;i++){ans[i]=Q.top();Q.pop();if(ans[i].r!=n) Q.push((node){ans[i].l,ans[i].r+1});}
}
int main()
{n=read();scanf("%lld%lld",&k0,&k1);k0=(ll)n*(n+1)/2-k0+1;k1=(ll)n*(n+1)/2-k1+1;swap(k0,k1);k1-=(k0-1);for(int i=1;i<=n;i++)z[i]=a[i]=read();sort(z+1,z+n+1);m=unique(z+1,z+n+1)-z-1;for(int i=1;i<=m;i++)t[i].push_back(0);for(int i=1;i<=n;i++)a[i]=lower_bound(z+1,z+m+1,a[i])-z,t[a[i]].push_back(i);for(int i=1;i<=m;i++)t[i].push_back(n+1);T1.build(1,1,n);    ans[1]=solve0();pw[0]=1;for(int i=1;i<=m;i++)pw[i]=pw[i-1]*W%mod;solve1();for(int i=k1;i;i--)printf("%d %d\n",ans[i].l,ans[i].r);    return 0;
}

[联合集训6-25] 蓝雨 线段树+主席树+hash相关推荐

  1. 线段树简单入门 (含普通线段树, zkw线段树, 主席树)

    线段树简单入门 递归版线段树 线段树的定义 线段树, 顾名思义, 就是每个节点表示一个区间. 线段树通常维护一些区间的值, 例如区间和. 比如, 上图 \([2, 5]\) 区间的和, 为以下区间的和 ...

  2. 2020-2021年度第二届全国大学生算法设计与编程挑战赛 (春季赛)- 天才的操作(线段树+主席树+树上倍增)

    题目链接:点击查看 题目分析:刚看到这个题目的时候,口胡了一个假算法,觉得对于每次询问的操作 [l,r][l,r][l,r] ,只需要找到指令集区间 [l,r][l,r][l,r] 内覆盖到点 kkk ...

  3. #6034. 「雅礼集训 2017 Day2」线段游戏 李超树

    #6034. 「雅礼集训 2017 Day2」线段游戏 内存限制:256 MiB时间限制:1000 ms标准输入输出 题目类型:传统评测方式:Special Judge 上传者: 匿名 提交提交记录统 ...

  4. 模板三连击:树状数组+线段树+主席树

    没事儿干,复习模板...... 1.树状数组 本来不想写这个的,但是反正就几分钟就打完了,所以就写了,水AC数. 洛谷 P3374 [模板]树状数组 1 1 #include<cstdio> ...

  5. 可持久化线段树——主席树

    前言: 最近心(po)血(yu)来(ya)潮(li)学习了一下主席树.(再不学就落伍了) 主席树,即可持久化线段树,支持维护和查询区间的第\(k\)大(小).区间不同种类个数等,基于线段树的思想之上 ...

  6. 牛客网 暑期ACM多校训练营(第一场)J.Different Integers-区间两侧不同数字的个数-离线树状数组 or 可持久化线段树(主席树)...

    J.Different Integers 题意就是给你l,r,问你在区间两侧的[1,l]和[r,n]中,不同数的个数. 两种思路: 1.将数组长度扩大两倍,for(int i=n+1;i<=2* ...

  7. Governing sand(权值线段树/主席树)

    链接:https://ac.nowcoder.com/acm/contest/887/C 来源:牛客网 时间限制:C/C++ 3秒,其他语言6秒 空间限制:C/C++ 65536K,其他语言13107 ...

  8. 【用学校抄作业带你走进可持久化线段树(主席树)】可持久化线段树概念+全套模板+例题入门:[福利]可持久化线段树)

    我似乎很少写这种算法博客 可持久化线段树概念 概念介绍(类比帮助理解) 简单分析一下时间和空间复杂度(内容池) 模板 结构体变量 建树模板 单点修改模板 单点查询模板 区间修改模板(pushup) 区 ...

  9. UOJ#218. 【UNR #1】火车管理 线段树 主席树

    原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ218.html 题解 如果我们可以知道每次弹出栈之后新的栈顶是什么,那么我们就可以在一棵区间覆盖.区间求和 ...

最新文章

  1. oracle, group by, having, where
  2. 逻辑 STANDBY ORA-00368日志应用失败处理一例
  3. macOS下nginx配合obs做推流直播.md
  4. 量化交易系统综述——互联网金融之二
  5. 2018美团笔试字符串问题
  6. 日本的“电力路由器”概述
  7. BAT 厮杀的小程序与手机厂商叫板的快应用,对开发者意味着什么?
  8. ++i 和 i++ 性能上的区别
  9. docker命令每次需要sudo操作解决方案
  10. 四十五.加密与解密 AIDE入侵检测系统 扫描与抓包
  11. java爬虫微信公众号信息_微信公众号爬虫项目(reptile)
  12. 软件结构体系与设计模式--1.软件设计模式概述
  13. 高通驱动程序开发参考(一)
  14. Python3 三元条件判断表达式(if else/and or)
  15. 概率论与统计的基础知识(概率空间、最基本的分布、数字特征)
  16. 一种简明易懂的专利侵权分析报告表单样式
  17. python感叹号的作用_Python的作用
  18. ASEMI线性稳压电源芯片AMS1117-3.3参数及接线电路图
  19. 【LeeCode】赛题02:Python解答大衍数列题目
  20. android gif动态显示,Android 显示Gif 动态图片

热门文章

  1. 随机编码生成器MD5加密字符串工具
  2. ​5.10.4 操作查询之​追加查询
  3. JAVA程序设计题——英雄对战游戏,定义一个描述战斗单位的英雄(Hero)类,此类必须包含以下成员变量:名称(name),生命值(life),技能1攻击力(damage1),防御力(defence)
  4. pytorch:线性回归实战
  5. 前端打包之后 运用nginx反向代理运行项目
  6. android flv视频播放器代码,音视频学习代码合集
  7. MySQL的binLog、redoLog、undoLog是什么?
  8. My dear dalao please daidai wo。
  9. 软件设计师提纲+复习资料整理(上午题)
  10. 分水岭算法的理解和应用