• 整体二分小结


    整体二分

            整体二分简单来说就是把所有修改和询问一起二分

      要求询问满足二分性,询问相互独立

         思想就是每次二分到一个答案,将询问划分到左右两个区间

      那么以什么作为划分依据呢?

      取决于操作对左右区间的贡献,如果有贡献就放到左区间 ,否则放入右区间,并将这次贡献的权值减去

      同时,用树状数组或线段树来维护贡献值

      注意每次操作完后要将修改还原

    例题:

    1. 区间第K小

    静态 :luogu P3834 

    Code :

    // luogu-judger-enable-o2
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<stack>
    #include<queue>
    using namespace std;
    typedef long long ll;
    
    const int maxn = 500010;
    const int INF = 1e9+7;
    
    int n,m,cnt; 
    int c[maxn];
    int ans[maxn];
    
    struct Node{
        int x,y,k,pos,qr;
    }q[maxn],q1[maxn],q2[maxn];
    
    void add(int x,int k){
        for(int i=x;i<=n;i+=i&(-i))
            c[i]+=k;
    }
    
    int sum(int x){
        int res=0;
        for(int i=x;i>0;i-=i&(-i))
            res+=c[i];
        return res;
    }
    
    void solve(int l,int r,int x,int y){
        if(l>r || x>y) return;
        if(l==r)
        {
            for(int i=x;i<=y;i++) if(q[i].qr) ans[q[i].pos]=l;
            return;
        }
        int mid=(l+r)>>1, cnt1=0, cnt2=0;
        for(int i=x;i<=y;i++){
            if(q[i].qr){
                int tmp=sum(q[i].y)-sum(q[i].x-1);
                if(tmp>=q[i].k) q1[++cnt1]=q[i];
                else q[i].k-=tmp,q2[++cnt2]=q[i];
            }else{
                if(q[i].x<=mid) q1[++cnt1]=q[i],add(q[i].pos,q[i].y);
                else q2[++cnt2]=q[i];
            }
        }
        for(int i=1;i<=cnt1;i++) if(!q1[i].qr) add(q1[i].pos,-q1[i].y);
        for(int i=1;i<=cnt1;i++) q[x+i-1]=q1[i];
        for(int i=1;i<=cnt2;i++) q[x+cnt1+i-1]=q2[i];
        solve(l,mid,x,x+cnt1-1); solve(mid+1,r,x+cnt1,y);
    }
    
    int read(){ int s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }
    
    int main(){
        n=read(),m=read();
        int x,y,k;
        for(int i=1;i<=n;i++){
            x=read(); q[++cnt]=(Node){x,1,0,i,0};
        }
        for(int i=1;i<=m;i++){
            x=read(),y=read(),k=read();
            q[++cnt]=(Node){x,y,k,i,1};
        }
        
        solve(-INF,INF,1,cnt);
        
        for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
        return 0;
    }
    View Code

    动态 :dynamic ranking

    Code :

    (留坑待填)

    2. POI  MET-Meteors

       询问是 n 个国家的陨石数量,注意可能爆long long ,如果答案已经超过询问的值要跳出。

    Code :

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<iostream>
    #include<cmath>
    #include<stack>
    #include<queue>
    #include<vector>
    using namespace std;
    typedef long long ll;
    
    const int maxn = 300030;
    const ll INF = 1e9+7;
    
    int n,m,K,cnt;
    ll ans[maxn],c[maxn];
    
    struct C{
        int l,r; ll w;
    }e[maxn];
    struct Q{
        int id; ll k;
    }q[maxn],q1[maxn],q2[maxn];
    
    vector<int> ar[maxn];
    
    void add(int x,ll v){
        for(int i=x;i<=m;i+=i&(-i))
            c[i]+=v;
    }
    
    ll sum(int x){
        ll res=0;
        for(int i=x;i>0;i-=i&(-i))
            res+=c[i];
        return res;
    } 
    
    void mdf(int u,int f){
        if(e[u].l>e[u].r) add(1,f*e[u].w);
        add(e[u].l,f*e[u].w); add(e[u].r+1,-f*e[u].w);
    }
    
    void solve(int l,int r,int x,int y){
        if(x>y) return;
        if(l==r){
            for(int i=x;i<=y;i++) ans[q[i].id]=l;
            return;
        }
        int mid=(l+r)>>1,cnt1=0,cnt2=0;
        for(int i=l;i<=mid;i++) mdf(i,1);
        ll tot;
        for(int i=x;i<=y;i++){
            tot=0;
            for(int j=0;j<ar[q[i].id].size();j++){
                tot+=sum(ar[q[i].id][j]);
                if(tot>=q[i].k) break;
            }
            if(tot>=q[i].k) q1[++cnt1]=q[i];
            else {
                q[i].k-=tot;
                q2[++cnt2]=q[i];
            }
        }
        for(int i=l;i<=mid;i++) mdf(i,-1);
        for(int i=1;i<=cnt1;i++) q[i+x-1]=q1[i];
        for(int i=1;i<=cnt2;i++) q[i+x+cnt1-1]=q2[i];
        solve(l,mid,x,x+cnt1-1); solve(mid+1,r,x+cnt1,y);
    }
    
    ll read(){ ll s=0,f=1; char ch=getchar(); while(ch<'0' || ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0' && ch<='9'){ s=s*10+ch-'0'; ch=getchar(); } return s*f; }
    
    int main(){
        n=read(),m=read();
        for(int i=1;i<=m;i++)
            ar[read()].push_back(i);
    
        for(int i=1;i<=n;i++){
            q[i].k=read(); q[i].id=i;
        }
        K=read();
        for(int i=1;i<=K;i++)
            e[i].l=read(),e[i].r=read(),e[i].w=read();
        ++K; e[K]=(C){1,m,INF};
        
        solve(1,K,1,n);
        
        for(int i=1;i<=n;i++) {
            if(ans[i]==K) printf("NIE\n");
            else printf("%lld\n",ans[i]);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    【剑指Offer】跳台阶&变态跳台阶
    【剑指Offer】替换空格
    【剑指Offer】二维数组中的查找
    【Leetcode】2. Add Two Numbers 两数相加
    HTML学习笔记(一)HTML的一些概念区别
    C#项目中一些文件类型说明
    数据结构初步归纳(一)概念、线性表以及队列和栈
    线程相关概念
    程序开发方法论
    C#集合类型
  • 原文地址:https://www.cnblogs.com/tuchen/p/10121704.html
Copyright © 2020-2023  润新知