zoukankan      html  css  js  c++  java
  • 整体二分

    随便写一点整体二分的东西。

    这个整体二分啊,非常的简单

    拿最简单的出来说吧

    poj2104

    n,m<=100000

    给一个长为n的数列a,有m个询问

    每次输入l,r,k询问al~ar中第k小的是哪一个。

    【solution】

    你们可能说主席树。

    然而有一个空间只要O(n)的做法,没错,就是整体二分。

    那么这个整体二分是什么呢。

    首先,我们把询问丢进一个struct 里面

    然后我们二分一个答案mid

    然后我们O(nlogn)求出每个询问的范围中<=mid的数的个数tot

    显然啊,如果这个数量tot>k的话,显然这个询问的答案就<mid

    那么我们现在就把所有的询问分成的两半。

    分治递归下去做。

    完了。时间O(nlogn^2)

    是不是很简单啊。

    以后出给学妹做,然后学妹写主席树空间被卡,

    哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈哈。

    但是注意一点哦,这个过程中询问的顺序一定要保证哦。

    否则的话,就乱套了。

    poj2104这个代码比较gay,去看后面那个比较好。

    #include<stdio.h>
    #include<stdlib.h>
    #include<iostream>
    #include<string>
    #include<string.h>
    #include<algorithm>
    #include<math.h>
    #define il inline
    #define re register
    #define lim 1e9
    #define lowbit(x) (x&(-x))
    using namespace std;
    const int N=1000001;
    struct data{int u,v;
    } a[N];
    struct query{int l,r,k,id,tot;
    } qu[N],qt[N];
    int n,m,c[N],ans[N];
    il int cmp(data a,data b){
        return a.v<b.v;
    }
    il void add(int p,int v){
        for(;p<=n;p+=lowbit(p)) c[p]+=v;
    }
    il int sum(int p){
        int ans=0;
        for(;p;p-=lowbit(p)) ans+=c[p];
        return ans;
    }
    il void conquer(int l,int r,int p,int q){
        int L=1,R=n+1,MID;
        while(L<R){
            MID=(L+R)/2;
            if(a[MID].v>=p) R=MID;
            else L=MID+1;
        }
        for(int i=R;i<=n&&a[i].v<=q;i++) add(a[i].u,1);
        for(int i=l;i<=r;i++)
            qu[i].tot=sum(qu[i].r)-sum(qu[i].l-1);
        for(int i=R;i<=n&&a[i].v<=q;i++) add(a[i].u,-1);
    }
    il void divide(int l,int r,int p,int q){
    //    cout<<l<<" "<<r<<" "<<p<<" "<<q<<endl;
        if(p==q){
            for(int i=l;i<=r;i++)
                ans[qu[i].id]=q;
            return;
        }
        int mid=p+(q-p)/2;
        conquer(l,r,p,mid);
        int L=l-1,R=r+1;
        for(int i=l;i<=r;i++){
            if(qu[i].tot>=qu[i].k) qt[++L]=qu[i];
            else{
                qu[i].k-=qu[i].tot;
                qt[--R]=qu[i];
            }
        }
        for(int i=l;i<=r;i++) qu[i]=qt[i];
        if(L>=l) divide(l,L,p,mid);
        if(R<=r) divide(R,r,mid+1,q);
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            a[i].u=i;
            scanf("%d",&a[i].v);
        }
        sort(a+1,a+n+1,cmp);a[n+1].v=lim;
        for(int i=1;i<=m;i++){
            scanf("%d%d%d",&qu[i].l,&qu[i].r,&qu[i].k);
            qu[i].id=i;
        }
        divide(1,m,-lim,lim);
        for(int i=1;i<=m;i++){
            printf("%d
    ",ans[i]);
        }
        return 0;
    }

    hdu5412

    就是前面一题加一个修改,

    这个也不虚,修改就是删掉一个数再加回来。

    和询问一样丢进去分治,直接按照数的大小拿去二分。

    重要的事情再讲一遍,注意顺序哦。

    自认为这个代码写的比较清楚。

    #include<stdio.h>
    #include<stdlib.h>
    #include<iostream>
    #include<string>
    #include<string.h>
    #include<algorithm>
    #include<math.h>
    #include<queue>
    #include<map>
    #include<vector>
    #include<set>
    #define il inline
    #define re register
    #define lim 1000000000
    #define lowbit(p) (p&(-p))
    using namespace std;
    const int N=1000001;
    struct edge{int u,v,w,id,tot;
    } a[N],d[N],e[N];
    int n,m,b[N],M,t[N],c[N],ans[N];
    il void add(int p,int v){
        for(;p<=n;p+=lowbit(p))    c[p]+=v;
    }
    il int sum(int p){
        int ans=0;
        for(;p;p-=lowbit(p)) ans+=c[p];
        return ans;
    }
    il void divide(int l,int r,int p,int q){
        if(p>q||l>r) return;
        if(p==q){
            for(int i=l;i<=r;i++)
                if(a[i].w) ans[a[i].id]=p;
            return;
        }
        int mid=(p+q)/2;
        for(int i=l;i<=r;i++){
            if(a[i].w) t[i]=sum(a[i].v)-sum(a[i].u-1);
            else if(a[i].u<=mid) add(a[i].id,a[i].v);
        }
        for(int i=l;i<=r;i++){
            if(a[i].u<=mid&&a[i].w==0) 
                add(a[i].id,-a[i].v);
        }
        int t1,t2,t3=l-1;t1=t2=0;
        for(int i=l;i<=r;i++){
            if(a[i].w){
                if(a[i].tot+t[i]>=a[i].w) d[++t1]=a[i];
                else{
                    a[i].tot+=t[i];e[++t2]=a[i];
                }
            } 
            else if(a[i].u<=mid) d[++t1]=a[i];
            else e[++t2]=a[i];
        }
        for(int i=1;i<=t1;i++) a[++t3]=d[i];
        for(int i=1;i<=t2;i++) a[++t3]=e[i];
        divide(l,l+t1-1,p,mid);divide(l+t1,r,mid+1,q);
    }
    il void init(){
        memset(ans,false,sizeof(ans));
        memset(c,false,sizeof(c));
        memset(t,false,sizeof(t));
        memset(b,false,sizeof(b));
        M=0;
        for(int i=1,x;i<=n;i++){
            scanf("%d",&x);b[i]=x;
            a[++M]=(edge){x,1,0,i,0};
        }
        scanf("%d",&m);
        for(int i=1,s,t,k,tp;i<=m;i++){
            scanf("%d%d%d",&tp,&s,&t);
            if(tp==1){
                a[++M]=(edge){b[s],-1,0,s,0};
                b[s]=t;
                a[++M]=(edge){b[s],1,0,s,0};
            }
            if(tp==2){
                scanf("%d",&k);
                a[++M]=(edge){s,t,k,i,0};
            }
        }
        divide(1,M,1,lim);
        for(int i=1;i<=m;i++)
            if(ans[i]) printf("%d
    ",ans[i]);
    }
    int main(){
        while(scanf("%d",&n)!=EOF) init();
        return 0;
    }

    ZJOI2013&bzoj3110

    有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c
    如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。

    N,M<=50000,N,M<=50000

    a<=b<=N

    1操作中abs(c)<=N

    2操作中c<=Maxlongint

    【solution】

    想了一会发现傻逼了。

    这不就是又改了一点嘛,感觉大概彻底理解这个算法了。

    网上不是树套树就是暴力瞎艹,

    这时候写一个整体二分就不错!

    就是添加的时候变成区修区查的树状数组就好了。

    #include<stdio.h>
    #include<stdlib.h>
    #include<iostream>
    #include<string>
    #include<string.h>
    #include<algorithm>
    #include<math.h>
    #include<queue>
    #include<map>
    #include<vector>
    #include<set>
    #define il inline
    #define re register
    #define lowbit(p) (p&(-p))
    using namespace std;
    typedef long long ll;
    const int N=1000001;
    struct edge{
        int u,v,w,id,tp,tot;
    } a[N],a1[N],a2[N];
    int n,m,M,ans[N];
    ll t[N],c[N][2];
    il void add(re int p,re ll v,re int k){
        for(;p<=n;p+=lowbit(p))
            c[p][k]+=v;
    }
    il ll sum(int p,int k){
        ll ans=0;
        for(;p;p-=lowbit(p)) 
            ans+=c[p][k];
        return ans;
    }
    il void addr(int l,int r,int v){
        add(l,v,0);add(r+1,-v,0);
        add(l,-(ll)v*(l-1),1);add(r+1,(ll)v*r,1);
    }
    il ll sumr(int r){
        return sum(r,0)*r+sum(r,1);
    }
    il ll val(int l,int r){
        return sumr(r)-sumr(l-1);
    }
    il void divide(int l,int r,int p,int q){
        if(l>r||p>q) return;
        if(p==q){
            for(int i=l;i<=r;i++) 
                if(a[i].tp==2) ans[a[i].id]=p;
            return;
        }
        int mid=p+(q-p)/2;
        for(int i=l;i<=r;i++){
            if(a[i].tp==2) t[i]=val(a[i].u,a[i].v);
            else if(a[i].w<=mid) addr(a[i].u,a[i].v,1);
        }
        for(int i=l;i<=r;i++)
            if(a[i].tp==1&&a[i].w<=mid) addr(a[i].u,a[i].v,-1);
        int t1,t2,t3=l-1;t1=t2=0;
        for(int i=l;i<=r;i++){
            if(a[i].tp==1){
                if(a[i].w<=mid) a1[++t1]=a[i];
                else a2[++t2]=a[i];
            }
            else{
                if(a[i].tot+t[i]>=a[i].w) a1[++t1]=a[i];
                else{
                    a[i].tot+=t[i];
                    a2[++t2]=a[i];
                }
            }
        }
        for(int i=1;i<=t1;i++) a[++t3]=a1[i];
        for(int i=1;i<=t2;i++) a[++t3]=a2[i];
        divide(l,l+t1-1,p,mid);
        divide(l+t1,r,mid+1,q);
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1,x,y,z,rp;i<=m;i++){
            scanf("%d%d%d%d",&rp,&x,&y,&z);
            if(rp==1) z=-z;
            a[++M]=(edge){x,y,z,i,rp,0};ans[i]=-1e9;
        }
        divide(1,m,-n,n);
        for(int i=1;i<=m;i++)
            if(ans[i]!=-1e9) printf("%d
    ",-ans[i]);
        return 0;
    }

     

  • 相关阅读:
    生成函数trick
    带权并查集维护二分图
    关于二项式反演的一些思考
    CSP集训记录
    解决Maven版本冲突
    蚂蚁金服5轮面试,最后栽这了...
    配置交换机Eth-Trunk+VRRP+MSTP+接口BFD状态联动+Telnet示例
    企业园区网络建设技术方案(华为)
    网络三层架构
    SOA治理
  • 原文地址:https://www.cnblogs.com/ExiledPoet/p/7062198.html
Copyright © 2011-2022 走看看