1. 程式人生 > >BZOJ5016 Snoi2017一個簡單的詢問(莫隊)

BZOJ5016 Snoi2017一個簡單的詢問(莫隊)

string 莫隊 ace cst truct print bsp for har

  容易想到區間轉化成前綴和。這樣每個詢問有了二維坐標,莫隊即可。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 50010
char getc(){char c=getchar();while ((c<A||c>Z)&&(c<
a||c>z)&&(c<0||c>9)) c=getchar();return c;} int gcd(int n,int m){return m==0?n:gcd(m,n%m);} int read() { int x=0,f=1;char c=getchar(); while (c<0||c>9) {if (c==-) f=-1;c=getchar();} while (c>=0&&c<=9) x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f; } int n,m,a[N],cntx[N],cnty[N],t,block; ll ans[N]; struct data { int k,x,y,i,op; bool operator <(const data&a) const { return k<a.k||k==a.k&&(k&1?y>a.y:y<a.y); } }q[N<<2]; int main() { #ifndef ONLINE_JUDGE freopen("bzoj5016.in"
,"r",stdin); freopen("bzoj5016.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(); for (int i=1;i<=n;i++) a[i]=read(); m=read();block=sqrt(n); for (int i=1;i<=m;i++) { int l1=read(),r1=read(),l2=read(),r2=read(); t++,q[t].x=r1,q[t].y=r2,q[t].i=i,q[t].op=1,q[t].k=q[t].x/block; t++,q[t].x=r1,q[t].y=l2-1,q[t].i=i,q[t].op=-1,q[t].k=q[t].x/block; t++,q[t].x=l1-1,q[t].y=r2,q[t].i=i,q[t].op=-1,q[t].k=q[t].x/block; t++,q[t].x=l1-1,q[t].y=l2-1,q[t].i=i,q[t].op=1,q[t].k=q[t].x/block; } sort(q+1,q+t+1); int x=0,y=0;ll cur=0; for (int i=1;i<=t;i++) { while (y<q[i].y) y++,cnty[a[y]]++,cur+=cntx[a[y]]; while (y>q[i].y) cur-=cntx[a[y]],cnty[a[y]]--,--y; while (x<q[i].x) x++,cntx[a[x]]++,cur+=cnty[a[x]]; while (x>q[i].x) cur-=cnty[a[x]],cntx[a[x]]--,--x; ans[q[i].i]+=q[i].op*cur; } for (int i=1;i<=m;i++) printf(LL,ans[i]); return 0; }

BZOJ5016 Snoi2017一個簡單的詢問(莫隊)