题目
给出一个长度为n的序列a[]
给出q组询问,每组询问形如
<x,y>
<script type="math/tex" id="MathJax-Element-13">
</script>,求a序列的所有区间中,数字x的出现次数与数字y的出现次数相同的区间有多少个。
数据范围
1<=n<=8000,1<=q<=500000,
1<=x,y,a[i]<=109
题解
很容易想到,每次询问的时候,
O(n)
扫一遍,有一临时变量t,碰到x,t加一,碰到y,t减一,看前面有多少个t等于现在的t,按照这个计算答案。
然而这样做有个缺点:每一次都要
O(n)
扫一遍,其中有很多段t一样的,其实可以不用跑这些没有用的位置。
将x和y出现的位置找出来,排个序,然后做一遍。
总时间复杂度
O(n2)
。
蒟蒻有个问题,怎么计算答案。
我们知道相邻两个位置之间的t是一样的,所以只要计算t=w(w为一个数)时的t的个数,即可得到答案。
代码
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define N 8010
#define P(a) putchar(a)
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
struct note{
int to,next;
};note edge[N*10];
struct note1{
int d,w;
};note1 qu[N*2];
int a[N],a1[N],b[N];
int o[N],head[N],q1[N],q2[N];
int ans[N][N];
int i,j,k,l,r,l1,r1,n,q,sum,wz,last;
int cnt[N*2],bz[N*2],cn,CNT,c1,c2,tot;
int read(){
int res=0,fh=1;char ch;
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')fh=-1,ch=getchar();
while(ch>='0'&&ch<='9')res=res*10+ch-'0',ch=getchar();
return res*fh;
}
void write(int x){
if(x>9)write(x/10);
P(x%10+'0');
}
int calc(int n){return n*(n+1)/2;}
int calc1(int n){return n*(n-1)/2;}
void lb(int x,int y){edge[++tot].to=y;edge[tot].next=head[x];head[x]=tot;}
bool cmp(note1 x,note1 y){return x.d<y.d;}
int main(){
freopen("query.in","r",stdin);
freopen("query.out","w",stdout);
n=read(),q=read();
fo(i,1,n)a[i]=read(),b[i]=a[i];
memcpy(a1,a,sizeof(a1));sort(b+1,b+n+1);cn=unique(b+1,b+n+1)-b-1;
fo(i,1,n){
a1[i]=lower_bound(b+1,b+cn+1,a1[i])-b;
o[a1[i]]=a[i];
}
fd(i,n,1)lb(a1[i],i);
fo(i,1,cn-1)
fo(j,i+1,cn){
c1=0;
for(k=head[i];k;k=edge[k].next)
qu[++c1].d=edge[k].to,qu[c1].w=1;
for(k=head[j];k;k=edge[k].next)
qu[++c1].d=edge[k].to,qu[c1].w=2;
sort(qu+1,qu+c1+1,cmp);
CNT++;
bz[8000]=CNT;cnt[8000]=qu[1].d;
qu[c1+1].d=n+1;
wz=8000;
ans[i][j]=calc1(qu[1].d);
fo(k,1,c1){
if(qu[k].w==1)wz++;else wz--;
if(CNT!=bz[wz]){
bz[wz]=CNT;
cnt[wz]=0;
}
ans[i][j]+=calc1(qu[k+1].d-qu[k].d)+cnt[wz]*(qu[k+1].d-qu[k].d);
cnt[wz]+=qu[k+1].d-qu[k].d;
}
ans[j][i]=ans[i][j];
}
fo(i,1,q){
l=read(),r=read();
l1=lower_bound(b+1,b+cn+1,l)-b;
r1=lower_bound(b+1,b+cn+1,r)-b;
if(o[l1]!=l)l=l1=0;if(o[r1]!=r)r=r1=0;
if((!l&&!r) ||(l1==r1)){
write(calc(n));P('\n');
continue;
}
if((!l&&r) || (!r&&l)){
sum=last=0;
if(r)l1=r1;
for(k=head[l1];k;k=edge[k].next){
sum+=calc(edge[k].to-1-last);
last=edge[k].to;
}
sum+=calc(n-last);
write(sum);P('\n');
continue;
}
write(ans[l1][r1]);
P('\n');
}
return 0;
}