J Different Integers
Given a sequence of integers a 1 , a 2 , …, a n and q pairs of integers (l 1 , r 1 ), (l 2 , r 2 ), …, (l q , r q ), find count(l 1 , r 1 ),count(l 2 , r 2 ), …, count(l q , r q ) where count(i, j) is the number of different integers among a 1 , a 2 , …, a i , a j , a j + 1 ,…, a n .
输入描述:
The input consists of several test cases and is terminated by end-of-file.
The first line of each test cases contains two integers n and q.
The second line contains n integers a 1 , a 2 , …, a n .
The i-th of the following q lines contains two integers l i and r i .
输出描述:
For each test case, print q integers which denote the result.
备注
* 1 ≤ n, q ≤ 10 5
* 1 ≤ a i ≤ n
* 1 ≤ l i , r i ≤ n
* The number of test cases does not exceed 10.
示例1:
输入
3 2
1 2 1
1 2
1 3
4 1
1 2 3 4
1 3
输出
2
1
3
题解:这题听直播题解的标准解法是树状数组,看了给的题解很久还是看不太懂,大佬的思想很活,之后看了别人2*n的内存空间的题解,得知原来可以这样:将a【i+n】=a【i】,就可以将1-i,j-n这样不连续的区间并集转化为连续的区间求并集,再用树状数组模板解即可。
#include<cstdio>
#include<map>
#include<algorithm>
using namespace std;
const int maxn=200000+100; ///括大一倍
int bit[maxn]; //树节点数组
int a[maxn]; //原数组
int Ans[maxn]; //询问结果
int n,m;
inline int lowbit(int x){
return x&(-x);
}
inline void Add(int x,int v){
while(x<=n){
bit[x]+=v;
x+=lowbit(x);
}
}
inline int getSum(int x){
int sum=0;
while(x>0){
sum+=bit[x];
x-=lowbit(x);
}
return sum;
}
struct Query{
int l,r;
int id;
}query[maxn];
inline bool cmp(Query aa,Query bb){
return aa.r<bb.r;
}
int main(){
map<int,int>M;
while(scanf("%d%d",&n,&m)==2){
M.clear();
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
a[n+i]=a[i];
bit[i]=bit[n+i]=0;
}
for(int i=1;i<=m;i++){
scanf("%d%d",&query[i].r,&query[i].l);
query[i].r+=n;
query[i].id=i;
}
n*=2;//扩大一倍
sort(query+1,query+m+1,cmp);
int pre=1;
for(int i=1;i<=m;i++){ //建树
for(int j=pre;j<=query[i].r;j++){
if(M[a[j]]!=0){
Add(M[a[j]],-1);
}
Add(j,1);
M[a[j]]=j;//标记
}
pre=query[i].r+1;
Ans[query[i].id]=getSum(query[i].r)-getSum(query[i].l-1);
}
for(int i=1;i<=m;i++) printf("%d\n",Ans[i]);
}
}
离线+莫队算法代码:
莫队算法的使用,我们只需要维护每个数出现的频率即可,当出现频率减到0时tmp值减一,当频率从0到1是,tmp值加一.
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=100005;
int q,m;
int s[maxn],vis[maxn],md[maxn],Ans[maxn];
struct Query{
int lef,rig,id;
}Que[maxn];
bool cmp(struct Query a,struct Query b)
{
//很重要!!!不然会TLE
if(md[a.lef]!=md[b.lef])return a.lef<b.lef;//先同一块l排序,不在同一块就r排序
return a.rig<b.rig;
}
void modui()
{
int i,lef=0,rig=q+1,ans=0;
for(i=1;i<=m;i++)
{
while(rig<Que[i].rig)
{
vis[s[rig]]--;
if(vis[s[rig]]==0)
ans--;
rig++;
}
while(rig>Que[i].rig)
{
rig--;
if(vis[s[rig]]==0)
ans++;
vis[s[rig]]++;
}
while(lef<Que[i].lef)
{
lef++;
if(vis[s[lef]]==0)
ans++;
vis[s[lef]]++;
}
while(lef>Que[i].lef)
{
vis[s[lef]]--;
if(vis[s[lef]]==0)
ans--;
lef--;
}
Ans[Que[i].id]=ans;
}
return ;
}
int main()
{
int i,temp;
while(scanf("%d%d",&q,&m)!=EOF)
{
memset(vis,0,sizeof(vis));
memset(Ans,0,sizeof(Ans));
temp=sqrt(q); //分块
for(i=1;i<=q;i++)
{
scanf("%d",&s[i]);
md[i]=(i-1)/temp+1; //所属块
}
for(i=1;i<=m;i++)
{
scanf("%d%d",&Que[i].lef,&Que[i].rig);
Que[i].id=i;
}
sort(Que+1,Que+m+1,cmp);
modui();
for(i=1;i<=m;i++)printf("%d\n",Ans[i]);
}
return 0;
}