HDU 5213 Lucky 离线莫队+容斥

版权声明:存在错误或者不清楚的地方还望指出 https://blog.csdn.net/hypHuangYanPing/article/details/82962375
/*
HDU 5213 Lucky  离线莫队+容斥;
链接:http://acm.hdu.edu.cn/showproblem.php?pid=5213
题意:所给两个区间各选一个数的和为k的二元组的数量;
分析:直接对两个区间进行莫队离线 显然是不可行的  移动的次数较多-->TLE;
考虑将两个区间进行合并 容斥原理
假设所选区间为 f(l,r) :表示区间[l,r]满足题意的二元组的数量;
G((l,r),(u,v)):表示对应两段区间满足条件的数量;

对于所给最大区间 则:f(l,v)=f(l,u-1)+f(r+1,v)-f(r+1,u-1)+G((l,r),(u,v));
确认每个区间相邻的状态,最后就是简单的莫队了,直接套用即可......
当然还有在线分块的写法  解法也比较自然;
*/

#include<bits/stdc++.h>
#define ll long long
using namespace std;

const int maxn=4e5+7;
int n,m,k,q,blo,pos[maxn];
int s[maxn],num[maxn];
int val[maxn];

struct node{
    int l,r,u,v,id,flag,num;
    bool operator <(const node &a)const{
        return pos[l]<pos[a.l]||(pos[l]==pos[a.l]&&r<a.r);
    }
}a[maxn];

int main(){
    while(~scanf("%d %d",&n,&k)){
        blo=(int)sqrt(n*1.0);
        for(int i=1;i<=n;i++) scanf("%d",&s[i]),pos[i]=(i-1)/blo+1;
        scanf("%d",&q);
        int cnt=1;
        for(int i=1;i<=q;i++) {
            int l,r,u,v;scanf("%d %d %d %d",&l,&r,&u,&v);
            a[cnt].l=l,a[cnt].r=v,a[cnt].num=1,a[cnt].id=i,cnt++;
            a[cnt].l=r+1,a[cnt].r=u-1,a[cnt].num=2,a[cnt].id=i,cnt++;
            a[cnt].l=l,a[cnt].r=u-1,a[cnt].num=3,a[cnt].id=i,cnt++;
            a[cnt].l=r+1,a[cnt].r=v,a[cnt].num=4,a[cnt].id=i,cnt++;
        }
        sort(a+1,a+cnt);
        memset(val,0,sizeof(val));
        memset(num,0,sizeof(num));
        int l=1,r=0,ret=0;
        for(int i=1;i<cnt;i++){
            if(a[i].l>a[i].r) continue;
            while(r<a[i].r){
                r++;
                num[s[r]]++;
                ret+=(k-s[r])>=0?num[k-s[r]]:0;
            }
            while(r>a[i].r){
                ret-=(k-s[r])>=0?num[k-s[r]]:0;
                num[s[r]]--;
                r--;
            }
            while(l>a[i].l){
                l--;
                num[s[l]]++;
                ret+=(k-s[l])>=0?num[k-s[l]]:0;
            }
            while(l<a[i].l){
                ret-=(k-s[l])>=0?num[k-s[l]]:0;
                num[s[l]]--;
                l++;
            }
            if(a[i].num<=2) val[a[i].id]+=ret;
            else val[a[i].id]-=ret;
        }
        for(int i=1;i<=q;i++) printf("%d\n",val[i]);
    }
    return 0;
}

/*
7
3
0 1 2 1 2 3 2
3
1 2 3 7
1 2 3 5
3 5 6 7
4 2 1

5
3
1 2 1 2 3
1
1 2 3 5
*/

猜你喜欢

转载自blog.csdn.net/hypHuangYanPing/article/details/82962375