zoukankan      html  css  js  c++  java
  • 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
    ",q[i].ans);
        }
    }
    View Code
  • 相关阅读:
    android 多线程
    Uva 10881 Piotr’s Ants 蚂蚁
    LA 3708 Graveyard 墓地雕塑 NEERC 2006
    UVa 11300 Spreading the Wealth 分金币
    UVa 11729 Commando War 突击战
    UVa 11292 The Dragon of Loowater 勇者斗恶龙
    HDU 4162 Shape Number
    HDU 1869 六度分离
    HDU 1041 Computer Transformation
    利用可变参数函数清空多个数组
  • 原文地址:https://www.cnblogs.com/ctyakwf/p/12586080.html
Copyright © 2011-2022 走看看