您的位置:首页 > 其它

牛客练习赛10 E 数列查找 [莫队+分块]

2018-01-20 18:32 239 查看
题意:给你长度为n的数列,m次询问,每次询问求【L,R】中,是第k1个次数的第k2个数是多少。

题解:很巧妙的解法,一开始想到的是莫队+线段树,转移时间为O(m*sqrt(m)*logn),得出结果时间为O(m*logn),所以总的时间复杂度为O(m*(sqrt(m)*logn+m*logn))就TLE了,可以看出主要的时间复杂度在转移上,所以我们可以通过减少转移的时间增加查询的时间,使得总的复杂度更低,于是可以采用分块的方法,我们需要四个数组:

int num
;//a[i]出现次数
int bcot[205],cot
;//次数类型的总数
int blo
[205];//该次数下数的个数


所以我们只需要O(1)转移,修改次数总和块的信息、某次数下数的个数的块的信息。然后查询的时候通过O(sqrt(n))查找第k1的次数是多少,与该次数下第k2的数是多少的信息,所以我们总的复杂度为O(m*(sqrt(m)+sqrt(n))就不会TLE了。

AC代码:

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#define N 50005
using namespace std;
int a
;
int real
,pos
;
int num
;//a[i]出现次数
int bcot[205],cot
;//次数类型的总数
int blo
[205];//该次数下数的个数
int len;
struct node
{
int l,r,k1,k2,id;
node(){}
node(int l,int r,int k1,int k2,int id)
{
this->l=r;
this->r=r;
this->k1=k1;
this->k2=k2;
this->id=id;
}
}q
;
int n,m;
int ans
;
bool cmp(node a,node b)
{
return pos[a.l]<pos[b.l]||pos[a.l]==pos[b.l]&&a.r<b.r;
}
int qcot(int need)
{
int sum=0;
for(int i=0;i<=len+1;i++)
{
sum+=bcot[i];
if(sum>=q[need].k1)
{
sum-=bcot[i];
for(int j=i*len;j<(i+1)*len;j++)
{
sum+=cot[j];
if(sum>=q[need].k1)
return j;
}
}
}
return -1;
}
int qnum(int cot,int need)
{
int sum=0;
for(int i=0;i<=len+1;i++)
{
sum+=blo[cot][i];
if(sum>=q[need].k2)
{
sum-=blo[cot][i];
for(int j=i*len;j<(i+1)*len;j++)
{
if(num[j]==cot)sum++;
if(sum>=q[need].k2)
return j;
}
}
}
while(1);
return -1;
}
void change(int number,int flag)
{
if(flag)
{
if(num[number]!=0)
{
blo[num[number]][number/len]--;
if(real[num[number]]==1)bcot[num[number]/len]--,cot[num[number]]--;
real[num[number]]--;
}

blo[++num[number]][number/len]++;
if(real[num[number]]==0)bcot[num[number]/len]++,cot[num[number]]++;
real[num[number]]++;
}
else
{
blo[num[number]][number/len]--;
if(real[num[number]]==1)bcot[num[number]/len]--,cot[num[number]]--;
real[num[number]]--;

if(num[number]!=1)
{
blo[--num[number]][number/len]++;
if(real[num[number]]==0)bcot[num[number]/len]++,cot[num[number]]++;
real[num[number]]++;
}
else num[number]--;
}
}
int main()
{
scanf("%d",&n);
len=(int)sqrt((double)n+0.1);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
scanf("%d",&m);
for(int i=1;i<=n;i++)
pos[i]=(i-1)/len+1;
for(int i=0;i<m;i++)
{
scanf("%d%d%d%d",&q[i].l,&q[i].r,&q[i].k1,&q[i].k2);
q[i].id=i;
}
sort(q,q+m,cmp);
int l=1,r=0;
for(int i=0;i<m;i++)
{
if(r<q[i].r)
{
for(r=r+1;r<=q[i].r;r++)
change(a[r],1);
r--;
}
if(q[i].l<l)
{
for(l=l-1;l>=q[i].l;l--)
change(a[l],1);
l++;
}
if(r>q[i].r)
{
for(;r>q[i].r;r--)
change(a[r],0);
}
if(q[i].l>l)
{
for(;l<q[i].l;l++)
change(a[l],0);
}
int now=qcot(i);
now=qnum(now,i);
ans[q[i].id]=now;
}
for(int i=0;i<m;i++)
printf("%d\n",ans[i]);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: