hdu 5213(莫队+容斥)

题意:

      n个数,一个k,m个询问,每个询问有[l1,r1] ,[l2,r2]两个区间,[l1,r1]中取x ,[l2,r2]中取y,使得x+y=k

(l1 <= r1 < l2 <= r2)


分析:

     根据容斥,F(l1,r1,l2,r2)=f(l1,r2)-f(r1+1,r2)-f(l1,l2-1)+f(r1+1,l2-1)。   记录下加减。

      这样可以把两个不相干的区间分成四个区间,然后就可以用莫队了。




#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<vector>
#include<cctype>
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<iomanip>
#include<sstream>
#include<limits>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
const int maxn = 2e5+10;
const ll MOD = 1000000007;
const double EPS = 1e-10;
const double Pi = acos(-1.0);
struct Node{
  int l,r,id,x,f;
}Q[maxn];
ll ans[maxn];
int a[maxn],num[maxn];
int unit;
bool cmp(Node a,Node b)
{
    if (a.x != b.x) return a.x < b.x;
    else return a.r<b.r;
}
int main(){
#ifdef LOCAL
	freopen("C:\\Users\\lanjiaming\\Desktop\\acm\\in.txt","r",stdin);
	//freopen("output.txt","w",stdout);
#endif
//ios_base::sync_with_stdio(0);
    int n,m,k;
    while(scanf("%d%d",&n,&k) != EOF)
    {
        for(int i = 1; i <= n; i++) scanf("%d",&a[i]);
        unit = (int)sqrt(n);
        scanf("%d",&m);
        for(int i = 0; i < m; i++)
        {
            int l1,l2,r1,r2;
            scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
            Q[i*4].l=l1;    Q[i*4].r=r2;    Q[i*4].id=i;  Q[i*4].f=1;
            Q[i*4+1].l=l1;  Q[i*4+1].r=l2-1;Q[i*4+1].id=i;Q[i*4+1].f=-1;
            Q[i*4+2].l=r1+1;Q[i*4+2].r=r2;  Q[i*4+2].id=i;Q[i*4+2].f=-1;
            Q[i*4+3].l=r1+1;Q[i*4+3].r=l2-1;Q[i*4+3].id=i;Q[i*4+3].f=1;
            Q[i*4].x = (Q[i*4].l-1) / unit + 1;
            Q[i*4+1].x = (Q[i*4+1].l-1) / unit + 1;
            Q[i*4+2].x = (Q[i*4+2].l-1) / unit + 1;
            Q[i*4+3].x = (Q[i*4+3].l-1) / unit + 1;
        }

        sort(Q,Q+m*4,cmp);

        memset(num,0,sizeof(num));
        memset(ans,0,sizeof(ans));
        int L = Q[0].l, R = Q[0].l-1;
        ll temp = 0;
        for(int i = 0;i < m*4;i++)
        {
            while(R < Q[i].r)
            {
                R++;
                if (k - a[R] > 0 && k - a[R] <= n) temp += num[k-a[R]];
                num[a[R]]++;
            }
            while(R > Q[i].r)
            {
                num[a[R]]--;
                if (k - a[R] > 0 && k - a[R] <= n) temp -= num[k-a[R]];
                R--;
            }
            while(L < Q[i].l)
            {
                num[a[L]]--;
                if (k - a[L] > 0 && k - a[L] <= n) temp -= num[k-a[L]];
                L++;
            }
            while(L > Q[i].l)
            {
                L--;
                if (k - a[L] > 0 && k - a[L] <= n) temp += num[k-a[L]];
                num[a[L]]++;
            }
            ans[Q[i].id] += temp*Q[i].f;
        }

        for(int i = 0; i < m; i++) printf("%lld\n",ans[i]);

    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值