Strange Queries (莫队+容斥原理)

题目传送门

题目大意:

给你一个长度为\(N\)的数列,求满足\(a_i = a_j\)\(l1\leq i \leq r1 , l2 \leq j \leq r2\)\((i,j)\)对数。

看到这种题目,第一反应就是莫队啦,但一看这个询问有点奇怪,不好算,怎么办呢?

这个时候就要用到容斥原理

至于怎么容斥,学过容斥原理的就可以跳过了。

首先:我们要求的答案一定\([l1,r2]\)(假设\(r1 < r2\))区间之内。很明显我们在这个区间内有许多答案是不需要的,那么就需要减去,比如\([l1,r1]\)自己配对或\([l1,r1]\)\([r1,l2]\)的配对,减去这些之后,我们发现区间\([r1,l2]\)会被减去两次,所以要加上来。

然后,我们就得到了美丽的关系式:

\[ Ans = ans[l1,r2] - ans[l1,l2] - ans[r1,r2] + ans[r1,l2] \]

为了保证复杂度,我们要把四个$ ans $放在四个询问中,所以要开四倍。

\(\mathcal{Code}\)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define get ch=getchar()
#define isd (ch>=48&&ch<=57)
#define ll long long
#define Re register
#define In inline
using namespace std;
const int maxn=5e5+1;
In int read(){
    char get;int r=0,s=1;
    while(!isd)s=ch==45?0:s,get;while(isd)r=(r<<1)+(r<<3)+(ch^48),get;
    return s?r:-r;
}

struct Q{int l,r,id;}q[maxn<<2];
int n,m,M,u,L,R;
ll Ans;
int a[maxn],pos[maxn];
ll ans[maxn],s[maxn];

bool cmp(Q a,Q b){return pos[a.l]==pos[b.l]?a.r<b.r:a.l<b.l;}

void add(int p){Ans+=s[a[p]]++;return;}

void sub(int p){Ans-=--s[a[p]];return;}

int main() {
    n=read();u=sqrt(n);
    for(Re int i=1;i<=n;i++)a[i]=read();
    for(Re int i=1;i<=n;i++)pos[i]=i/u+1;
    M=read();
    for(Re int i=1,a,b,c,d;i<=M;i++){
        a=read(),b=read()+1,c=read()-1,d=read();
        q[++m]=(Q){a,d,i};q[++m]=(Q){a,c,-i};
        q[++m]=(Q){b,d,-i};q[++m]=(Q){b,c,i};
    }
    sort(q+1,q+m+1,cmp);
    L=n+1,R=n;
    for(Re int i=1;i<=m;i++){
        while(L<q[i].l)sub(L++);
        while(L>q[i].l)add(--L);
        while(R>q[i].r)sub(R--);
        while(R<q[i].r)add(++R);
        if(q[i].id>0)ans[q[i].id]+=Ans;
        else ans[-q[i].id]-=Ans;
    }
    for(int i=1;i<=M;i++)printf("%lld\n",ans[i]);
    return 0;
}

转载于:https://www.cnblogs.com/dclicker/p/10160760.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值