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

    整体二分,就是对答案(权值)做CDQ分治。

    有些问题会给出一些修改和一些询问,当可以通过二分后线性判定回答询问时,我们就可以将所有修改和询问放在一起二分,复杂度一般会将一个O(n)级别优化掉,这就是整体二分。

    一般配合树状数组、线段树等数据结构,来替代树套树、KD-Tree等代码量和常数都较大的方法。

    [BZOJ1901][Zju2112] Dynamic Rankings

    动态区间第k小是整体二分最经典的应用。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     4 using namespace std;
     5 
     6 const int N=30010;
     7 char ch;
     8 int n,m,x,y,z,tot,cnt,a[N],tmp[N],ans[N],c[N];
     9 struct P{ int x,y,z,op,id; }q[N],q1[N],q2[N];
    10 
    11 void add(int x,int k){ for (; x<=n; x+=x&-x) c[x]+=k; }
    12 int que(int x){ int res=0; for (; x; x-=x&-x) res+=c[x]; return res; }
    13 
    14 void solve(int st,int ed,int l,int r){
    15     if (st>ed) return;
    16     if (l==r){ rep(i,st,ed) ans[q[i].id]=l; return; }
    17     int mid=(l+r)>>1,tot1=0,tot2=0;
    18     rep(i,st,ed){
    19         if (q[i].op==1){
    20             if (q[i].y<=mid) add(q[i].x,1),q1[++tot1]=q[i]; else q2[++tot2]=q[i];
    21         }
    22         if (q[i].op==2){
    23             if (q[i].y<=mid) add(q[i].x,-1),q1[++tot1]=q[i]; else q2[++tot2]=q[i];
    24         }
    25         if (q[i].op==3){
    26             int t=que(q[i].y)-que(q[i].x-1);
    27             if (q[i].z<=t) q1[++tot1]=q[i]; else q[i].z-=t,q2[++tot2]=q[i];
    28         }
    29     }
    30     rep(i,1,tot1){
    31         if (q1[i].op==1) add(q1[i].x,-1);
    32         if (q1[i].op==2) add(q1[i].x,1);
    33     }
    34     rep(i,1,tot1) q[st+i-1]=q1[i];
    35     rep(i,1,tot2) q[st+tot1+i-1]=q2[i];
    36     solve(st,st+tot1-1,l,mid);
    37     solve(st+tot1,ed,mid+1,r);
    38 }
    39 
    40 int main(){
    41     freopen("bzoj1901.in","r",stdin);
    42     freopen("bzoj1901.out","w",stdout);
    43     scanf("%d%d",&n,&m);
    44     rep(i,1,n) scanf("%d",&a[i]),q[++tot]=(P){i,a[i],0,1,0};
    45     rep(i,1,m){
    46         scanf(" %c",&ch);
    47         if (ch=='Q') scanf("%d%d%d",&x,&y,&z),q[++tot]=(P){x,y,z,3,++cnt};
    48             else scanf("%d%d",&x,&y),q[++tot]=(P){x,a[x],0,2,0},a[x]=y,q[++tot]=(P){x,y,0,1,0};
    49     }
    50     solve(1,tot,0,1e9);
    51     rep(i,1,cnt) printf("%d
    ",ans[i]);
    52     return 0;
    53 }
    BZOJ1901

    [BZOJ2527][POI2011]Meteors

    显然我们可以对每个询问二分,然后O(n)判定。考虑整体二分,用now标记当前处于的是哪个位置的状态,每次暴力调整,均摊是O(nlogn)的。

     1 #include<cstdio>
     2 #include<vector>
     3 #include<algorithm>
     4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     5 typedef long long ll;
     6 using namespace std;
     7 
     8 const int N=300010,inf=1e9;
     9 ll c[N];
    10 int n,m,l,r,k,Q,tot,now,co[N],d[N],a[N],a1[N],a2[N],ans[N];
    11 struct P{ int l,r,k; }q[N];
    12 vector<int>ve[N];
    13 
    14 void add(int x,int k){ for (; x<=m; x+=x&-x) c[x]+=k; }
    15 ll que(int x){ ll res=0; for (; x; x-=x&-x) res+=c[x]; return res; }
    16 
    17 void work(int x,int k){
    18     add(q[x].l,k*q[x].k),add(q[x].r+1,-k*q[x].k);
    19     if (q[x].l>q[x].r) add(1,k*q[x].k);
    20 }
    21 
    22 void solve(int st,int ed,int l,int r){
    23     if (st>ed) return;
    24     if (l==r){ rep(i,st,ed) ans[a[i]]=l; return; }
    25     int mid=(l+r)>>1;
    26     while (now<mid) work(++now,1);
    27     while (now>mid) work(now--,-1);
    28     int tot1=0,tot2=0;
    29     rep(i,st,ed){
    30         int en=ve[a[i]].size()-1; ll res=0;
    31         rep(j,0,en){
    32             res+=que(ve[a[i]][j]);
    33             if (res>=d[a[i]]) break;
    34         }
    35         if (res>=d[a[i]]) a1[++tot1]=a[i]; else a2[++tot2]=a[i];
    36     }
    37     rep(i,1,tot1) a[st+i-1]=a1[i];
    38     rep(i,1,tot2) a[st+tot1+i-1]=a2[i];
    39     solve(st,st+tot1-1,l,mid);
    40     solve(st+tot1,ed,mid+1,r);
    41 }
    42 
    43 int main(){
    44     freopen("bzoj2527.in","r",stdin);
    45     freopen("bzoj2527.out","w",stdout);
    46     scanf("%d%d",&n,&m);
    47     rep(i,1,m) scanf("%d",&co[i]),ve[co[i]].push_back(i);
    48     rep(i,1,n) scanf("%d",&d[i]),a[i]=i;
    49     scanf("%d",&Q);
    50     rep(i,1,Q) scanf("%d%d%d",&l,&r,&k),q[i]=(P){l,r,k};
    51     q[Q+1]=(P){1,m,inf};
    52     solve(1,n,1,Q+1);
    53     rep(i,1,n) if (ans[i]==Q+1) puts("NIE"); else printf("%d
    ",ans[i]);
    54     return 0;
    55 }
    BZOJ2527

    [BZOJ3110][ZJOI2013]K大数查询

    同BZOJ1901,注意树状数组区间修改单点查询的方法。

    http://www.cnblogs.com/RabbitHu/p/BIT.html

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     4 typedef long long ll;
     5 using namespace std;
     6 
     7 const int N=100010;
     8 ll c1[N],c2[N];
     9 int n,m,op,l,r,k,cnt,tot,ans[N];
    10 struct P{ int l,r,k,op,id; }q[N],q1[N],q2[N];
    11 
    12 void add(int x,int k){ for (int i=x; i<=n; i+=i&-i) c1[i]+=k,c2[i]+=1ll*x*k; }
    13 
    14 ll que(int x){
    15     ll res1=0,res2=0;
    16     for (int i=x; i; i-=i&-i) res1+=c1[i],res2+=c2[i];
    17     return (x+1)*res1-res2;
    18 }
    19 
    20 void solve(int st,int ed,int l,int r){
    21     if (st>ed) return;
    22     if (l==r){ rep(i,st,ed) ans[q[i].id]=l; return; }
    23     int mid=(l+r+1)>>1,tot1=0,tot2=0;
    24     rep(i,st,ed){
    25         if (q[i].op==1){
    26             if (q[i].k>=mid) add(q[i].l,1),add(q[i].r+1,-1),q2[++tot2]=q[i];
    27                 else q1[++tot1]=q[i];
    28         }else{
    29             int t=que(q[i].r)-que(q[i].l-1);
    30             if (q[i].k<=t) q2[++tot2]=q[i];
    31                 else q[i].k-=t,q1[++tot1]=q[i];
    32         }
    33     }
    34     rep(i,1,tot2) if (q2[i].op==1) add(q2[i].l,-1),add(q2[i].r+1,1);
    35     rep(i,1,tot1) q[st+i-1]=q1[i];
    36     rep(i,1,tot2) q[st+tot1+i-1]=q2[i];
    37     solve(st,st+tot1-1,l,mid-1);
    38     solve(st+tot1,ed,mid,r);
    39 }
    40 
    41 int main(){
    42     freopen("bzoj3110.in","r",stdin);
    43     freopen("bzoj3110.out","w",stdout);
    44     scanf("%d%d",&n,&m);
    45     rep(i,1,m) scanf("%d%d%d%d",&op,&l,&r,&k),q[++tot]=(P){l,r,k,op,(op==1)?0:++cnt};
    46     solve(1,m,-n,n);
    47     rep(i,1,cnt) printf("%d
    ",ans[i]);
    48     return 0;
    49 }
    BZOJ3110

    [BZOJ2738]矩阵乘法

    同BZOJ1901,改成二维树状数组即可。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     4 using namespace std;
     5 
     6 const int N=510,M=320010;
     7 int n,Q,mx,tot,x,x1,y1,x2,y2,k,cnt,ans[M],c[N][N];
     8 struct P{ int x1,y1,x2,y2,k,op,id; }q[M],q1[M],q2[M];
     9 
    10 void add(int x,int y,int k){
    11     for (int i=x; i<=n; i+=i&-i)
    12         for (int j=y; j<=n; j+=j&-j) c[i][j]+=k;
    13 }
    14 
    15 int que(int x,int y){
    16     int res=0;
    17     for (int i=x; i; i-=i&-i)
    18         for (int j=y; j; j-=j&-j) res+=c[i][j];
    19     return res;
    20 }
    21 
    22 void solve(int st,int ed,int l,int r){
    23     if (st>ed) return;
    24     if (l==r){ rep(i,st,ed) ans[q[i].id]=l; return; }
    25     int mid=(l+r)>>1,tot1=0,tot2=0;
    26     rep(i,st,ed) if (q[i].op==1){
    27         if (q[i].x2<=mid) add(q[i].x1,q[i].y1,1),q1[++tot1]=q[i];
    28         else q2[++tot2]=q[i];
    29     }else{
    30         int t=que(q[i].x2,q[i].y2)-que(q[i].x1-1,q[i].y2)-que(q[i].x2,q[i].y1-1)+que(q[i].x1-1,q[i].y1-1);
    31         if (q[i].k<=t) q1[++tot1]=q[i]; else q[i].k-=t,q2[++tot2]=q[i];
    32     }
    33     rep(i,1,tot1) if (q1[i].op==1) add(q1[i].x1,q1[i].y1,-1);
    34     rep(i,1,tot1) q[st+i-1]=q1[i];
    35     rep(i,1,tot2) q[st+tot1+i-1]=q2[i];
    36     solve(st,st+tot1-1,l,mid); solve(st+tot1,ed,mid+1,r);
    37 }
    38 
    39 int main(){
    40     freopen("bzoj2738.in","r",stdin);
    41     freopen("bzoj2738.out","w",stdout);
    42     scanf("%d%d",&n,&Q); int mx=0;
    43     rep(i,1,n) rep(j,1,n) scanf("%d",&x),q[++tot]=(P){i,j,x,0,0,1,0},mx=max(mx,x);
    44     rep(i,1,Q) scanf("%d%d%d%d%d",&x1,&y1,&x2,&y2,&k),q[++tot]=(P){x1,y1,x2,y2,k,2,++cnt};
    45     solve(1,tot,0,mx);
    46     rep(i,1,cnt) printf("%d
    ",ans[i]);
    47     return 0;
    48 }
    BZOJ2738
  • 相关阅读:
    android studio导出apk
    Android开发入门经典实例
    L1-Day32
    L1-Day33
    L1-Day30
    Oracle中的null与空字符串''的区别
    Oracle中的job(定时任务)
    Oracle中的加解密函数
    LeetCode33题——搜索旋转排序数组
    Oracle中的DBMS_LOCK包的使用
  • 原文地址:https://www.cnblogs.com/HocRiser/p/10349603.html
Copyright © 2011-2022 走看看