【JZOJ5296】【清华集训2017模拟】Sequence

Description

这里写图片描述

Data Constraint

这里写图片描述

Solution

对于S和S’,我们可以用主席树很轻松的求出,但不能求出二关键字的k大。所以我们考虑整体二分。我们可以求出排名在[x,y]内的元素的范围[a,b]。对于一个范围[l,r]设满足排名k在该区间的询问[x,y],我们二分出mid,对于一个询问,若满足区间[l,r]内第一关键字在[a,b]且满足第二关键字小于mid的数量少于k,则答案一定在[l,mid]内。因为满足区间[l,r]内因为第二关键字是排列,我们将第二关键字在[l,mid]内的元素按位置排序,并将询问拆成[1,l-1],[1,r]两个询问,然后维护一个指针时期插入的数的位置小于询问,将第一关键字插入至树状数组查询即可。时间复杂度O( Nlog2N )。

Code

#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=3e4+5,maxn1=2e5+5;
struct code{
    int l,r,num;
}f[maxn*20];
struct code2{
    int x,id;
}c[maxn]; 
struct code1{
    int l,r,x,y,k,id;
}q[maxn1],q1[maxn1];
int a[maxn1],b[maxn1],d[maxn1],ans[maxn1],g[maxn1];
int n,m,i,t,j,k,l,x,y,z,num;
bool cmp(code2 x,code2 y){
    return x.x<y.x;
}
bool cmp1(code2 x,code2 y){
    return x.id<y.id;
}
bool cmp2(code1 x,code1 y){
    return x.l<y.l;
}
void insert(int l,int r,int &v,int x){
    int mid=(l+r)/2;
    f[++num]=f[v];v=num;f[v].num++;
    if (l==r) return;
    if (mid>=x) insert(l,mid,f[v].l,x);
    else insert(mid+1,r,f[v].r,x);
}
void find(int l,int r,int v,int v1,int x){
    int mid=(l+r)/2;
    if (l==r){
        t=l;return;
    }
    if (x>f[f[v].l].num-f[f[v1].l].num) find(mid+1,r,f[v].r,f[v1].r,x-(f[f[v].l].num-f[f[v1].l].num));
    else find(l,mid,f[v].l,f[v1].l,x);
}
void insert1(int x,int z){
    while (x<=n) g[x]+=z,x+=(x&(-x));
}
int find1(int x){
    int t=0;
    while (x>0) t+=g[x],x-=(x&(-x));
    return t;
}
void dg(int l,int r,int x,int y){
    int mid=(l+r)/2;
    if (x>y) return;
    if (l==r){
        for (i=x;i<=y;i++)
            ans[q[i].id]=l;
        return;
    }
    sort(c+l,c+mid+1,cmp1);
    num=0;
    for (i=x;i<=y;i++){
        q1[++num]=q[i];q1[++num]=q[i];q1[num-1].l--;
        q1[num].l=q[i].r;q1[num-1].r=-1;q1[num].r=1;
    }
    sort(q1+1,q1+num+1,cmp2);j=l;
    for (i=1;i<=num;i++){
        while (c[j].id<=q1[i].l && j<=mid) insert1(a[c[j++].id],1);
        d[q1[i].id]+=(find1(q1[i].y)-find1(q1[i].x-1))*q1[i].r;
    }j--;
    while (j>=l) 
        insert1(a[c[j--].id],-1);
    int num=0;
    for (i=x;i<=y;i++)
        if (ans[q[i].id]+d[q[i].id]>=q[i].k) q1[++num]=q[i];
    int t=num;
    for (i=x;i<=y;i++)
        if (ans[q[i].id]+d[q[i].id]<q[i].k) q1[++num]=q[i],ans[q[i].id]+=d[q[i].id];
    for (i=x;i<=y;i++)q[i]=q1[i-x+1],d[q[i].id]=0;
    sort(c+l,c+mid+1,cmp);
    dg(l,mid,x,x+t-1);dg(mid+1,r,x+t,y);
}
int main(){
    freopen("sequence.in","r",stdin);freopen("sequence.out","w",stdout);
    scanf("%d",&n);
    for (i=1;i<=n;i++)
        scanf("%d",&a[i]),d[i]=d[i-1],insert(1,n,d[i],a[i]);
    for (i=1;i<=n;i++)scanf("%d",&b[i]),c[i].x=b[i],c[i].id=i;
    sort(c+1,c+n+1,cmp);
    scanf("%d",&m);
    for (i=1;i<=m;i++){
        scanf("%d%d%d%d%d",&q[i].l,&q[i].r,&x,&y,&q[i].k);q[i].id=i;
        t=0;find(1,n,d[q[i].r],d[q[i].l-1],x);q[i].x=t;
        t=0;find(1,n,d[q[i].r],d[q[i].l-1],y);q[i].y=t;
    }
    memset(d,0,sizeof(d));
    dg(1,n,1,m);
    for (i=1;i<=m;i++) printf("%d\n",ans[i]);
}
发布了257 篇原创文章 · 获赞 451 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/crybymyself/article/details/77512425