bzoj5016 [Snoi2017]一个简单的询问

传送门

分析

我们发现可以通过容斥得到Ans = sum(1,R1,1,R2) - sum(1,R1,1,L2-1) - sum(1,L1-1,1,R2) + sum(1,L1-1,L2-1)

于是我们可以吧一个询问分成4部分

然后进行莫队即可

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
#define int long long
int belong[400100],block,n,m,num1[400100],num2[400100],ans[400100],Ans,a[400100],cnt;
struct node {
    int le,ri,id,wh;
};
node d[400100];
inline bool cmp(const node a,const node b){
    if(belong[a.le]==belong[b.le])return a.ri<b.ri;
    return a.le<b.le;
}
signed main(){
    int i,j,k,L=1,R=0;
    scanf("%lld",&n);
    block=sqrt(n);
    for(i=1;i<=n;i++)belong[i]=(i-1)/block+1;
    for(i=1;i<=n;i++)scanf("%lld",&a[i]);
    scanf("%lld",&m);
    for(i=1;i<=m;i++){
      int x1,x2,y1,y2;
      scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
      d[++cnt]=(node){y1,y2,i,1};
      d[++cnt]=(node){x1-1,y2,i,-1};
      d[++cnt]=(node){y1,x2-1,i,-1};
      d[++cnt]=(node){x1-1,x2-1,i,1};
    }
    sort(d+1,d+cnt+1,cmp);
    for(i=1;i<=cnt;i++){
      while(L>d[i].le){
          Ans-=num2[a[L]];
          num1[a[L]]--;
          L--;
      }
      while(L<d[i].le){
          L++;
          Ans+=num2[a[L]];
          num1[a[L]]++;
      }
      while(R<d[i].ri){
          R++;
          Ans+=num1[a[R]];
          num2[a[R]]++;
      }
      while(R>d[i].ri){
          Ans-=num1[a[R]];
          num2[a[R]]--;
          R--;
      }
      ans[d[i].id]+=d[i].wh*Ans;
    }
    for(i=1;i<=m;i++)printf("%lld\n",ans[i]);
    return 0;
}
posted @ 2019-03-13 23:04  水题收割者  阅读(99)  评论(0编辑  收藏  举报