题目大意
一个长度为
n
n
的序列,每个元素都是。
一个区间代表的序列是将其元素排序。
现在求出区间代表序列字典序按高到低排名在区间
[p,q]
[
p
,
q
]
的区间。
q-p<=100000。
做法
我们如何快速比较两个区间代表序列的字典序?
主席树维护区间哈希即可。
那么只要我知道第p个,可以用经典做法推到第q个。
关键是第p个。
考虑逐位确定,每位二分有多少个。
已经确定了一些位后,每个左端点的合法右端点是一段区间。
线段树维护即可。
#include<cstdio>
#include<algorithm>
#include<queue>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
#define mp make_pair
using namespace std;
typedef long long ll;
typedef pair<int,int> pi;
const int maxn=100000+10,maxtot=10000000+10,mo1=1000000007,mo2=998244353;
int root[maxn],tree[maxtot][2],left[maxtot],right[maxtot],ci[maxtot],cm[maxn][2];
ll num[maxn*4],sum[maxn*4];
int mi[maxn*4],mx[maxn*4],mim[maxn*4],mxm[maxn*4],st[maxn*4],rs[maxn*4],cnt[maxn];
bool bz[maxn*4],pd[maxn*4];
int last[maxn],lft[maxn],sta[maxn],a[maxn];
int i,j,k,l,r,lc,rc,mid,t,n,m,tot,top;
ll p,q,wdc,xdl,zjy;
int read(){
int 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;
}
pi getha(int x,int y){
int j=tree[y][0]-tree[x][0];
(j+=mo1)%=mo1;
int k=tree[y][1]-tree[x][1];
(k+=mo2)%=mo2;
return mp(j,k);
}
int newnode(int x){
tot++;
tree[tot][0]=tree[x][0];
tree[tot][1]=tree[x][1];
left[tot]=left[x];
right[tot]=right[x];
ci[tot]=ci[x];
return tot;
}
void insert(int &x,int l,int r,int a){
x=newnode(x);
(tree[x][0]+=cm[a-1][0])%=mo1;
(tree[x][1]+=cm[a-1][1])%=mo2;
if (l==r){
ci[x]++;
return;
}
int mid=(l+r)/2;
if (a<=mid) insert(left[x],l,mid,a);else insert(right[x],mid+1,r,a);
}
int compare(int x1,int y1,int x2,int y2,int l,int r){
if (l==r){
int j=ci[y1]-ci[x1],k=ci[y2]-ci[x2];
if (j==k) return 0;
else if (j<k) return -1;
else return 1;
}
if (getha(x1,y1)==getha(x2,y2)) return 0;
int mid=(l+r)/2;
if (getha(left[x1],left[y1])==getha(left[x2],left[y2])) return compare(right[x1],right[y1],right[x2],right[y2],mid+1,r);
else return compare(left[x1],left[y1],left[x2],left[y2],l,mid);
}
bool cmp(int l1,int r1,int l2,int r2){
int t=compare(root[l1-1],root[r1],root[l2-1],root[r2],1,n);
if (t==-1) return 1;
else if (t==0&&l1>l2) return 1;
else return 0;
}
struct dong{
int l,r;
friend bool operator <(dong a,dong b){
return cmp(a.l,a.r,b.l,b.r);
}
} zlt;
priority_queue<dong> heap;
void build(int p,int l,int r){
if (l==r){
num[p]=mx[p]=mim[p]=l;
sum[p]=mi[p]=mxm[p]=n;
return;
}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
num[p]=num[p*2]+num[p*2+1];
sum[p]=sum[p*2]+sum[p*2+1];
mi[p]=mi[p*2];
mim[p]=mim[p*2];
mx[p]=mx[p*2+1];
mxm[p]=mxm[p*2+1];
}
void markbz(int p,int l,int r,int x){
bz[p]=1;
st[p]=x;
mx[p]=mim[p]=x;
num[p]=(ll)(r-l+1)*x;
}
void markpd(int p,int l,int r,int x){
pd[p]=1;
rs[p]=x;
mi[p]=mxm[p]=x;
sum[p]=(ll)(r-l+1)*x;
}
void down(int p,int l,int r){
int mid=(l+r)/2;
if (bz[p]){
markbz(p*2,l,mid,st[p]);
markbz(p*2+1,mid+1,r,st[p]);
bz[p]=0;
}
if (pd[p]){
markpd(p*2,l,mid,rs[p]);
markpd(p*2+1,mid+1,r,rs[p]);
pd[p]=0;
}
}
ll query(int p,int l,int r,int a,int b,int x){
if (l==r){
if (mi[p]<x) return 0;
else if (mx[p]<x) return mi[p]-x+1;
else return mi[p]-mx[p]+1;
}
down(p,l,r);
if (l==a&&r==b){
int mid=(l+r)/2;
if (mi[p]<x){
if (mi[p*2+1]<x) return query(p*2+1,mid+1,r,mid+1,b,x);
else return query(p*2,l,mid,a,mid,x)+query(p*2+1,mid+1,r,mid+1,b,x);
}
else if (mx[p*2]<x) return sum[p*2]-(ll)(x-1)*(mid-l+1)+query(p*2+1,mid+1,r,mid+1,b,x);
else return query(p*2,l,mid,a,mid,x)+sum[p*2+1]-num[p*2+1]+(r-mid);
}
int mid=(l+r)/2;
if (b<=mid) return query(p*2,l,mid,a,b,x);
else if (a>mid) return query(p*2+1,mid+1,r,a,b,x);
else return query(p*2,l,mid,a,mid,x)+query(p*2+1,mid+1,r,mid+1,b,x);
}
void reset(int p,int l,int r,int a,int b,int j,int s){
if (mim[p]==mxm[p]+1){
if (mi[p]<j){
markbz(p,l,r,j);
markpd(p,l,r,j-1);
}
else if (mx[p]>s){
markbz(p,l,r,s+1);
markpd(p,l,r,s);
}
return;
}
//return;
if (l==r){
if (mi[p]<j){
markbz(p,l,r,j);
markpd(p,l,r,j-1);
}
else if (mx[p]>s){
markbz(p,l,r,s+1);
markpd(p,l,r,s);
}
else{
if (mx[p]<j) markbz(p,l,r,j);
if (mi[p]>s) markpd(p,l,r,s);
}
return;
}
down(p,l,r);
if (l==a&&r==b){
int mid=(l+r)/2;
if (mi[p]<j){
if (mi[p*2+1]<j){
markbz(p*2,l,mid,j);
markpd(p*2,l,mid,j-1);
reset(p*2+1,mid+1,r,mid+1,b,j,s);
}
else{
reset(p*2,l,mid,a,mid,j,s);
reset(p*2+1,mid+1,r,mid+1,b,j,s);
}
}
else if (mx[p]>s){
if (mx[p*2]>s){
markbz(p*2+1,mid+1,r,s+1);
markpd(p*2+1,mid+1,r,s);
reset(p*2,l,mid,a,mid,j,s);
}
else{
reset(p*2,l,mid,a,mid,j,s);
reset(p*2+1,mid+1,r,mid+1,b,j,s);
}
}
else{
bool czy=0,gjx=0;
if (mx[p*2]<j){
markbz(p*2,l,mid,j);
gjx=1;
}
else czy=1;
if (mi[p*2+1]>s){
markpd(p*2+1,mid+1,r,s);
czy=1;
}
else gjx=1;
//return;
if (czy) reset(p*2,l,mid,a,mid,j,s);
//return;
if (gjx) reset(p*2+1,mid+1,r,mid+1,b,j,s);
}
num[p]=num[p*2]+num[p*2+1];
sum[p]=sum[p*2]+sum[p*2+1];
mi[p]=mi[p*2];
mim[p]=mim[p*2];
mx[p]=mx[p*2+1];
mxm[p]=mxm[p*2+1];
return;
}
int mid=(l+r)/2;
if (b<=mid) reset(p*2,l,mid,a,b,j,s);
else if (a>mid) reset(p*2+1,mid+1,r,a,b,j,s);
else{
reset(p*2,l,mid,a,mid,j,s);
reset(p*2+1,mid+1,r,mid+1,b,j,s);
}
num[p]=num[p*2]+num[p*2+1];
sum[p]=sum[p*2]+sum[p*2+1];
mi[p]=mi[p*2];
mim[p]=mim[p*2];
mx[p]=mx[p*2+1];
mxm[p]=mxm[p*2+1];
}
ll check(int x,int k){
int i,j,l,r;
ll t=0;
fo(i,k,top){
l=sta[i+1]+1;r=sta[i];
j=sta[i-k+1];
t+=query(1,1,n,l,r,j);
}
return t;
}
void modify(int x,int k){
if (k){
reset(1,1,n,sta[k]+1,n,n+1,n);
}
int i,j,s,l,r;
fo(i,max(k,1),top){
l=sta[i+1]+1;r=sta[i];
j=sta[i-k+1];s=sta[i-k]-1;
reset(1,1,n,l,r,j,s);
}
}
void travel(int p,int l,int r){
if (l==r){
//printf("%d %d\n",mx[p],mi[p]);
if (mx[p]==mi[p]){
wdc--;
if (!wdc){
lc=l;
rc=mx[p];
}
}
return;
}
down(p,l,r);
int mid=(l+r)/2;
travel(p*2,l,mid);
travel(p*2+1,mid+1,r);
}
int main(){
freopen("data.in","r",stdin);freopen("data.out","w",stdout);
n=read();
cm[0][0]=cm[0][1]=1;
fo(i,1,n){
cm[i][0]=(ll)cm[i-1][0]*(n+1)%mo1;
cm[i][1]=(ll)cm[i-1][1]*(n+1)%mo2;
}
scanf("%lld%lld",&p,&q);
fo(i,1,n){
a[i]=read();
cnt[a[i]]++;
lft[i]=last[a[i]];
last[a[i]]=i;
root[i]=root[i-1];
insert(root[i],1,n,a[i]);
}
build(1,1,n);
wdc=p;
fo(i,1,n){
top=0;
j=last[i];
while (j){
sta[++top]=j;
j=lft[j];
}
sta[0]=n+1;sta[top+1]=0;
xdl=check(i,1);
if (xdl<wdc){
wdc-=xdl;
modify(i,0);
continue;
}
l=1;r=cnt[i]+1;
/*while (l<r){
mid=(l+r)/2;
if (check(i,mid)<wdc) r=mid;else l=mid+1;
}*/
while (l<=r){
mid=(l+r)/2;
zjy=check(i,mid);
if (zjy<wdc){
k=mid;
xdl=zjy;
r=mid-1;
}
else l=mid+1;
}
wdc-=xdl;
//k=l-1;
k--;
modify(i,k);
}
travel(1,1,n);
j=n;
fo(i,1,n){
if (i==lc){
j=rc;
zlt.l=i;zlt.r=j;
heap.push(zlt);
continue;
}
while (!cmp(i,j,lc,rc)) j--;
while (j<n&&cmp(i,j+1,lc,rc)) j++;
zlt.l=i;zlt.r=j;
heap.push(zlt);
}
/*fo(i,1,n){
zlt.l=i;zlt.r=n;
heap.push(zlt);
}*/
wdc=q-p+1;
while (wdc--){
zlt=heap.top();
heap.pop();
printf("%d %d\n",zlt.l,zlt.r);
if (zlt.r>zlt.l){
zlt.r--;
heap.push(zlt);
}
}
}