HDU5213 Lucky(莫队+容斥)

这道题能看的出可以离线查询,不难想到莫队,但是寻常莫队每个询问只有一段,这样只需要排序即可

这里有两段,如果只按一段排序,那么复杂度显然得不到保证,以后不知道后面一段怎么样。

因此这里提出了一个想法就是,如果有多段,那么可以通过容斥原理来解决这个问题,把他变成多个询问的加减,这样复杂度就ok了

我们想要查询的是取两个数使他的和为k,从纸上画画就知道应该如何容斥。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<cmath>
#include<iostream>
using namespace std;
typedef long long ll;
const int  N=1e5+10;
struct node{
    int x1,x2;
    int y1,y2;
    ll ans;
}q[N<<1];
struct Node{
    int l,r;
    ll ans;
    int fa;
    int flag;
}s[N<<1];
int a[N],k;
int pos[N];
ll cnt[N];
ll res;
bool cmp(Node a,Node b){
    if(pos[a.l]==pos[b.l])
        return a.r<b.r;
    return pos[a.l]<pos[b.l];
}
void add(int x){
    if(k-a[x]>0)
    res+=cnt[k-a[x]];
    cnt[a[x]]++;
}
void sub(int x){
    cnt[a[x]]--;
    if(k-a[x]>0)
    res-=cnt[k-a[x]];
}
int main(){
    int n;
    int i;
    while(cin>>n){
        cin>>k;
        res=0;
        for(i=1;i<=n;i++)
            cnt[i]=0;
        int block=sqrt(n);
        for(i=1;i<=n;i++){
            scanf("%d",&a[i]);
            pos[i]=(i-1)/block+1;
        }
        int m;
        cin>>m;
        int cnt=0;
        for(i=1;i<=m;i++){
            scanf("%d%d%d%d",&q[i].x1,&q[i].y1,&q[i].x2,&q[i].y2);
            q[i].ans=0;
            cnt++;
            s[cnt].l=q[i].x1,s[cnt].r=q[i].y2,s[cnt].ans=0,s[cnt].fa=i,s[cnt].flag=1;
            cnt++;
            s[cnt].l=q[i].y1+1,s[cnt].r=q[i].x2-1,s[cnt].ans=0,s[cnt].fa=i,s[cnt].flag=1;
            cnt++;
            s[cnt].l=q[i].x1,s[cnt].r=q[i].x2-1,s[cnt].ans=0,s[cnt].fa=i,s[cnt].flag=0;
            cnt++;
            s[cnt].l=q[i].y1+1,s[cnt].r=q[i].y2,s[cnt].ans=0,s[cnt].fa=i,s[cnt].flag=0;
        }
        sort(s+1,s+1+cnt,cmp);
        int l=1;
        int r=0;
        for(i=1;i<=cnt;i++){
            while(s[i].l<l)
                add(--l);
            while(s[i].l>l)
                sub(l++);
            while(s[i].r>r)
                add(++r);
            while(s[i].r<r)
                sub(r--);
            s[i].ans=res;
            int x=s[i].fa;
            int flag=s[i].flag;
            if(flag){
                q[x].ans+=s[i].ans;
            }
            else{
                q[x].ans-=s[i].ans;
            }
        }
        for(i=1;i<=m;i++)
            printf("%lld\n",q[i].ans);
    }
}
View Code

 

posted @ 2020-03-28 10:23  朝暮不思  阅读(124)  评论(0编辑  收藏  举报