HDU 5213 Lucky 容斥+莫队

来源:互联网 发布:最终幻想14 mac 编辑:程序博客网 时间:2024/06/03 13:40
HDU 5213
题意:给出长度为n的序列a,和一个奇数K. 
m次询问[l,r,u,v] l<=r<u<=v.问从[l,r],[u,v]两个区间中分别选一个数x,y.问满足x+y=k的(x,y)对数
n,m<=3e4. a[i]<=n.

记录两组询问区间中每个数的出现频率 增加一个数时容易知道它的贡献,莫队排序后离线一下.
[l,r,u,v] 每个询问有两个区间 不能直接排序? 所以把这两个不相关的区间拆成4个独立的区间 .f[l,r]为l,r内两数加为k的对数.

res[l,r,u,v] = f[l,v] - f[l,u-1] - f[r+1,v] + f[r+1,u-1]. 

#include <bits/stdc++.h>using namespace std;typedef long long ll;const int N=3e4+5,M=4*N;struct node{    int l,r,id,sig;}q[M];int n,k,Q,res,tot,a[N],pos[N],fre[N],ans[N];void init(){    res=0,tot=0;    memset(fre,0,sizeof(fre));    int block=sqrt(n);    for(int i=1;i<=n;i++)        pos[i]=(i-1)/block+1;}bool cmp(node a,node b){    if(pos[a.l]==pos[b.l])        return a.r<b.r;    return a.l<b.l;}void add(int p){    int x=a[p];    if(x>k)        return;    fre[x]++;    res+=fre[k-x];}void del(int p){    int x=a[p];    if(x>k)        return;    res-=fre[k-x];    fre[x]--;}void solve(){    for(int i=1,l=1,r=0;i<=tot;i++)    {        for(;r<q[i].r;r++)            add(r+1);        for(;l>q[i].l;l--)            add(l-1);        for(;r>q[i].r;r--)            del(r);        for(;l<q[i].l;l++)            del(l);        ans[q[i].id]+=q[i].sig * res;    }}int main(){    while(~scanf("%d%d",&n,&k))    {        for(int i=1;i<=n;i++)            scanf("%d",&a[i]);        init();        scanf("%d",&Q);        int l,r,u,v;        for(int i=1;i<=Q;i++)        {            ans[i]=0;            scanf("%d%d%d%d",&l,&r,&u,&v);            q[++tot].l=l,q[tot].r=v,q[tot].id=i,q[tot].sig=1;            q[++tot].l=l,q[tot].r=u-1,q[tot].id=i,q[tot].sig=-1;            q[++tot].l=r+1,q[tot].r=v,q[tot].id=i,q[tot].sig=-1;            if(r+1<=u-1)                q[++tot].l=r+1,q[tot].r=u-1,q[tot].id=i,q[tot].sig=1;        }        sort(q+1,q+1+tot,cmp);        solve();        for(int i=1;i<=Q;i++)            printf("%d\n",ans[i]);    }    return 0;}


原创粉丝点击