题意:有一个数组 a[] 长度为n.
q组询问,每组询问[L,R]表示询问a1……aL,aR……an中有多少个不同的数字。n,q=1e5.
令an+i=ai,将原数组a[]的长度扩大为2n
原询问等价于[R,n+L],即询问aR……an,an+1,……,an+L中有多少个不同的数字。
莫队思想:利用 询问的离线性 和 答案支持连续的端点修改 两个性质,调整询问的顺序。
我们依据 询问的左端点的值 把所有的询问区间分为√n 组,每一组的长度是√n ,左端点值为x,则这个询问落在第(x/√n+1)组。
各组组内也要排序,组内的顺序即右端点的值从小到大。
具体做法:将所有询问排序,第一关键字为组号,第二关键字为右端点的值。
假设我们已经维护了一个结构,它可以求出一个询问的答案,并且维护了这个询问区间内每个数出现的次数。
那么:从一个询问到另一个询问,有两种情况:
①两个询问属于同组:最多修改√n 次左端点,修改ki次右端点
设该组内有mj个询问,则回答完这个组的询问的复杂度为:O(mj×√n +Σki),(其中Σki<=n,Σmj=n). 即O(mj×√n +n)
②两个询问属于不同组:可以放弃当前维护的询问,另行维护(求出)一个结构,复杂度为O(n)
这种情况由于组号数,最多出现O(√n)次。
所有更换组的总复杂度O(n√n);求所有组内询问的总复杂度:ΣO(mj×√n +n)=ΣO(mj×√n)+√nO(n)=O(n√n)。这两种操作是并列(互斥)的,所以总复杂度O(n√n).
--就是因为根号的缘故可能被卡--
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int a[200010];
int sq1e5=316;
struct quest
{
int i,lef,rig;
int ans;
int group;
}s[100010];
int vis[100001];
bool my(quest a,quest b)
{
if(a.group==b.group) return a.rig<b.rig;
else return a.group<b.group;
}
bool re(quest a,quest b)
{
return a.i<b.i;
}
int read()
{
int x=0; char ch=getchar();
if(ch==EOF) exit(0);
while(!isdigit(ch)) ch=getchar();
while(isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();}
return x;
}
void put(int x)
{
if(x==0){putchar('0'); putchar('\n'); return;}
if(x<0){putchar('-'); x=-x;}
int num=0; char ch[16];
while(x) ch[++num]=x%10+'0',x/=10;
while(num) putchar(ch[num--]);
putchar('\n');
}
int add(int i,int f)
{
if(f==1)
{
if(vis[i]){++vis[i];return 0;}
else{++vis[i];return 1;}
}
else
{
--vis[i];
if(vis[i])return 0;
else return -1;
}
}
int main()
{
//ios::sync_with_stdio(false);
//cin.tie(0);cout.tie(0);
int n=read(),q=read();
do
{
for(int i=1;i<=n;++i) {a[i]=read();a[n+i]=a[i];}
for(int i=1;i<=q;++i)
{
s[i].rig=read()+n;s[i].lef=read();
s[i].i=i;
//s[i].rig+=n;
s[i].group=s[i].lef/sq1e5+1;
}
sort(s+1,s+1+q,my);
int lef=n,rig=n+1;
int cnt=0;
memset(vis,0,sizeof(vis));
for(int i=1;i<=q;++i)
{
if(s[i].group>s[i-1].group)
{
memset(vis,0,sizeof(vis));
cnt=0;
lef=s[i].lef;
rig=s[i].rig;
for(int o=n;o>=lef;--o) cnt+=add(a[o],1);
for(int o=n+1;o<=rig;++o) cnt+=add(a[o],1);
s[i].ans=cnt;
}
else
{
if(lef<s[i].lef)
{
for(int o=lef;o<s[i].lef;++o)
{
cnt+=add(a[o],-1);
}
}
else
{
for(int o=lef-1;o>=s[i].lef;--o)
{
cnt+=add(a[o],1);
}
}
lef=s[i].lef;
for(int o=rig+1;o<=s[i].rig;++o)
{
cnt+=add(a[o],1);
}
rig=s[i].rig;
s[i].ans=cnt;
}
}
sort(s+1,s+1+q,re);
for(int i=1;i<=q;++i)
{
put(s[i].ans);
}
}while(n=read(),q=read());
return 0;
} 


京公网安备 11010502036488号