HDU 5213 Lucky(莫队+容斥)

 

给出 n 个数和数字 k,有 m 此询问,每次给出两个区间 [l,r] [u,v] ,问每次询问时,从两个区间内各选一个数字 x,y ,问有多少个二元组使得 x+y=k 成立

本来是打算直接用两个莫队来维护这两个区间,但是超时了,想想也是,有 e7 的级数

这个题可以将这两个区间和并,因为注意到 l,r,u,v 的关系是单调递增的,所以合并之后用一个莫队来解决,为了满足题目中所说,分别从两个区间中选择 x,y ,所以从区间 [r+1,v] 和 [l,u-1] 中选择的另一个数字是不合法的,所以要从总数中减去,又根据容斥原理,[r+1,u-1] 这个区间被减了两次,所以要重新加回来

最后别忘了询问数组要开4倍 

const int N=3e4+5;

    int i,j,k;
    int n,m,t;
    int a[N];
    struct Node
    {
        int l,r;
        int bel,id,tag;
        Node(int l=0,int r=0,int tag=0,int bel=0,int id=0):l(l),r(r),tag(tag),bel(bel),id(id){}
        bool operator<(Node o){
            if(bel==o.bel) return r<o.r;
            return l<o.l;
        }
    }q[N<<2];
    int cnt[N],cur,ans[N],block;

void add(int pos)
{
    int x=a[pos];
    if(k-x>0 && k-x<n) cur+=cnt[k-x];
    if(x>0 && x<=n) cnt[x]++;
}

void del(int pos)
{
    int x=a[pos];
    if(x>0 && x<=n) cnt[x]--;
    if(k-x>0 && k-x<n) cur-=cnt[k-x];
}

int main()
{
    //IOS;
    while(~sdd(n,k)){
        for(int i=1;i<=n;i++) sd(a[i]),cnt[i]=0;
        sd(m); block=sqrt(n);
        int num=1,l,r,u,v;
        for(int i=1;i<=m;i++){
            sdd(l,r); sdd(u,v);
            ans[i]=0;
            q[num++]=Node(l,v,1,l/block,i);
            q[num++]=Node(r+1,v,-1,(r+1)/block,i);
            q[num++]=Node(l,u-1,-1,l/block,i);
            q[num++]=Node(r+1,u-1,1,(r+1)/block,i);
        }
        sort(q+1,q+num);
        l=1,r=0; cur=0;
        for(int i=1;i<num;i++){
            while(l>q[i].l) add(--l);
            while(l<q[i].l) del(l++);
            while(r>q[i].r) del(r--);
            while(r<q[i].r) add(++r);
            ans[q[i].id]+=cur*q[i].tag;
        }
        for(int i=1;i<=m;i++) pd(ans[i]);
    }
    //PAUSE;
    return 0;
}

 

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页