【LOJ2254】【SNOI2017】一个简单的询问
莫队算法即可。
本题粗看似乎无从下手,考虑将一个询问拆成多个前缀询问。
设,,我们有
于是用莫队计算即可。
用两个数组分别维护两个前缀中每个数的出现次数,增删数时可以更新答案。
时间复杂度 。
#include <bits/stdc++.h>using namespace std;typedef long long ll;const int MAXSIZE=10000020;int bufpos;char buf[MAXSIZE];#define NEG 0void init(){#ifdef LOCALfreopen("2254.txt","r",stdin);#endifbuf[fread(buf,1,MAXSIZE,stdin)]='\0';bufpos=0;}#if NEGint readint(){bool isneg;int val=0;for(;!isdigit(buf[bufpos]) && buf[bufpos]!='-';bufpos++);bufpos+=(isneg=buf[bufpos]=='-');for(;isdigit(buf[bufpos]);bufpos++)val=val*10+buf[bufpos]-'0';return isneg?-val:val;}#elseint readint(){int val=0;for(;!isdigit(buf[bufpos]);bufpos++);for(;isdigit(buf[bufpos]);bufpos++)val=val*10+buf[bufpos]-'0';return val;}#endifchar readchar(){for(;isspace(buf[bufpos]);bufpos++);return buf[bufpos++];}int readstr(char* s){int cur=0;for(;isspace(buf[bufpos]);bufpos++);for(;!isspace(buf[bufpos]);bufpos++)s[cur++]=buf[bufpos];s[cur]='\0';return cur;}ll ans[50001],now;int a[50001],cnt[2][50001],pl[50001];struct query{int p,sgn,l1,l2;bool operator <(const query& rhs)const{return pl[l1]!=pl[rhs.l1]?pl[l1]<pl[rhs.l1]:l2<rhs.l2;}}q[200001];void update(int p,int v,int sgn){now+=sgn*cnt[p^1][v];cnt[p][v]+=sgn;}int main(){init();int n=readint(),cur=0;for(int i=1;i<=n;i++)a[i]=readint();int m=readint();for(int i=1;i<=m;i++){int l1=readint()-1,r1=readint(),l2=readint()-1,r2=readint();if (l1)q[++cur]=(query){i,-1,l1,r2};if (l2)q[++cur]=(query){i,-1,l2,r1};if (l1 && l2)q[++cur]=(query){i,1,l1,l2};q[++cur]=(query){i,1,r1,r2};}int sz=sqrt(n)+0.5;for(int i=1;i<=n;i++)pl[i]=(i-1)/sz+1;sort(q+1,q+cur+1);int l1=0,l2=0;for(int i=1;i<=cur;i++){while(l1<q[i].l1)update(0,a[++l1],1);while(l1>q[i].l1)update(0,a[l1--],-1);while(l2<q[i].l2)update(1,a[++l2],1);while(l2>q[i].l2)update(1,a[l2--],-1);ans[q[i].p]+=now*q[i].sgn;}for(int i=1;i<=m;i++)printf("%lld\n",ans[i]);}
本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。
本文链接:https://www.q234rty.top/2017/08/02/loj2254/
