CSU 1515 Sequence(莫隊演算法)
阿新 • • 發佈:2019-02-07
Description
給出一個長度為n的序列ai,進行m次查詢,每次查詢區間[l,r]中滿足|ai-aj|=1的(i,j)對數(l<=i < j<=r)
Input
第一行為兩整數n和m表示序列長度和查詢次數,第二行n個整數ai表示該序列,最後m行每行兩個整數l和r表示查詢區間(1<=n<=10^4,1<=m<=10^5,0<=ai< 2^31)
Output
輸出每次查詢的答案
Sample Input
10 10
5 5 1 3 6 3 5 7 1 7
3 4
6 8
8 9
2 8
5 7
6 7
1 9
3 10
3 10
5 6
Sample Output
0
0
0
3
1
0
4
3
3
0
Solution
莫隊,給所有操作首先按左端點平方分塊,然後將每個區間左端點所處塊的編號為第一關鍵字,右端點為第二關鍵字排序,之後按順序在區間間遞推即可
Code
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<map>
using namespace std;
#define maxn 11111
struct node
{
int l,r,id,ans;
}q[10*maxn ];
int n,m,ans,a[maxn],pos[maxn];
map<int,int>cnt;
int cmp1(node x,node y)
{
if(pos[x.l]!=pos[y.l])return x.l<y.l;
return x.r<y.r;
}
int cmp2(node x,node y)
{
return x.id<y.id;
}
void update(int x,int v)
{
x=a[x];
cnt[x]+=v;
ans+=cnt[x+1]*v;
if(x)ans+=cnt[x -1]*v;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
cnt.clear();
int mm=(int)sqrt(n);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
pos[i]=(i-1)/mm+1;
}
for(int i=0;i<m;i++)
{
scanf("%d%d",&q[i].l,&q[i].r);
q[i].id=i;
}
sort(q,q+m,cmp1);
ans=0;
int l=1,r=0;
for(int i=0;i<m;i++)
{
while(r<q[i].r)update(r+1,1),r++;
while(r>q[i].r)update(r,-1),r--;
while(l<q[i].l)update(l,-1),l++;
while(l>q[i].l)update(l-1,1),l--;
q[i].ans=ans;
}
sort(q,q+m,cmp2);
for(int i=0;i<m;i++)printf("%d\n",q[i].ans);
}
return 0;
}