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

    鬼知道为什么这一个sb专题我咕了这么久

    整体的二分->整体二分

    众所周知,做一些题的时候二分答案时间复杂度是$O(nlogn)$的,但当询问次数也是$O(n)$的时候时间复杂度就是$O(n^2logn)$的,GG

    整体二分就是在每次二分询问的操作本质差别不大时,把所有操作用一次二分求出,这样时间复杂度就还是$O(nlogn)$的;

    一般都会套一些数据结构在里面处理询问,最常用的是树状数组,加起来时间复杂度就是$O(nlog^2n)$的;

    跟cdq分治有一定区别,cdq分治是把问题转化为偏序问题然后二分分治,问题性质要满足左右不会互相影响;

    而整体二分更像是在二分答案的同时分治操作,根据操作是否满足二分出来的两个值域来向下分治;

    整体二分主要适用于一些数据结构题,但cdq的相同点是都需要离线,所以不适用于强制在线的问题。

    例题

    (都挺水的)

    【POJ2104】Kth Number

    静态区间K小,模板题

     1 #include<algorithm>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cstdio>
     5 #include<cmath>
     6 #include<queue>
     7 #define inf 2147483647
     8 #define eps 1e-9
     9 #define lb(x) (x&-x)
    10 using namespace std;
    11 typedef long long ll;
    12 typedef double db;
    13 struct task{
    14     int op,id,x,y,v;
    15     task(){}
    16     task(int _op,int _id,int _x,int _y,int _v){
    17         op=_op,id=_id,x=_x,y=_y,v=_v;
    18     }
    19 }t[500001],t1[500001],t2[500001];
    20 int n,m,mi=inf,mx=-inf,x,y,k,cnt=0,ans[500001],tr[500001];
    21 void add(int x,int v){
    22     for(;x<=n;x+=lb(x)){
    23         tr[x]+=v;
    24     }
    25 }
    26 int query(int x){
    27     int ret=0;
    28     for(;x;x-=lb(x)){
    29         ret+=tr[x];
    30     }
    31     return ret;
    32 }
    33 void solve(int ql,int qr,int l,int r){
    34     if(ql>qr||l>r)return;
    35     if(ql==qr){
    36         for(int i=l;i<=r;i++){
    37             if(t[i].op)ans[t[i].id]=ql;
    38         }
    39         return;
    40     }
    41     int mid=(ql+qr)/2,cnt1=0,cnt2=0;
    42     for(int i=l;i<=r;i++){
    43         if(t[i].op){
    44             int nw=query(t[i].y)-query(t[i].x-1);
    45             if(nw>=t[i].v)t1[++cnt1]=t[i];
    46             else{
    47                 t[i].v-=nw;
    48                 t2[++cnt2]=t[i];
    49             }
    50         }else{
    51             if(t[i].v<=mid){
    52                 t1[++cnt1]=t[i];
    53                 add(t[i].id,t[i].x);
    54             }else t2[++cnt2]=t[i];
    55         }
    56     }
    57     for(int i=1;i<=cnt1;i++){
    58         if(!t1[i].op){
    59             add(t1[i].id,-t1[i].x);
    60         }
    61     }
    62     for(int i=1;i<=cnt1;i++)t[i+l-1]=t1[i];
    63     for(int i=1;i<=cnt2;i++)t[i+l+cnt1-1]=t2[i];
    64     solve(ql,mid,l,l+cnt1-1);
    65     solve(mid+1,qr,l+cnt1,r);
    66 }
    67 int main(){
    68     scanf("%d%d",&n,&m);
    69     for(int i=1;i<=n;i++){
    70         scanf("%d",&x);
    71         mi=min(mi,x);
    72         mx=max(mx,x);
    73         t[++cnt]=task(0,i,1,0,x);
    74     }
    75     for(int i=1;i<=m;i++){
    76         scanf("%d%d%d",&x,&y,&k);
    77         t[++cnt]=task(1,i,x,y,k);
    78     }
    79     solve(mi,mx,1,cnt);
    80     for(int i=1;i<=m;i++){
    81         printf("%d
    ",ans[i]);
    82     }
    83     return 0;
    84 }

    【BZOJ1901】Zju2112 Dynamic Rankings

    带修改区间K小,依然是模板题,但是比树套树好写多了

     1 #include<algorithm>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cstdio>
     5 #include<cmath>
     6 #include<queue>
     7 #define inf 2147483647
     8 #define eps 1e-9
     9 #define lb(x) (x&-x)
    10 using namespace std;
    11 typedef long long ll;
    12 typedef double db;
    13 struct task{
    14     int op,id,x,y,v;
    15     task(){}
    16     task(int _op,int _id,int _x,int _y,int _v){
    17         op=_op,id=_id,x=_x,y=_y,v=_v;
    18     }
    19 }t[500001],t1[500001],t2[500001];
    20 int n,m,mi=inf,mx=-inf,x,y,k,totq=0,cnt=0,num[500001],ans[500001],tr[500001];
    21 char op[5]; 
    22 void add(int x,int v){
    23     for(;x<=n;x+=lb(x)){
    24         tr[x]+=v;
    25     }
    26 }
    27 int query(int x){
    28     int ret=0;
    29     for(;x;x-=lb(x)){
    30         ret+=tr[x];
    31     }
    32     return ret;
    33 }
    34 void solve(int ql,int qr,int l,int r){
    35     if(ql>qr||l>r)return;
    36     if(ql==qr){
    37         for(int i=l;i<=r;i++){
    38             if(t[i].op)ans[t[i].id]=ql;
    39         }
    40         return;
    41     }
    42     int mid=(ql+qr)/2,cnt1=0,cnt2=0;
    43     for(int i=l;i<=r;i++){
    44         if(t[i].op){
    45             int nw=query(t[i].y)-query(t[i].x-1);
    46             if(nw>=t[i].v)t1[++cnt1]=t[i];
    47             else{
    48                 t[i].v-=nw;
    49                 t2[++cnt2]=t[i];
    50             }
    51         }else{
    52             if(t[i].v<=mid){
    53                 t1[++cnt1]=t[i];
    54                 add(t[i].id,t[i].x);
    55             }else t2[++cnt2]=t[i];
    56         }
    57     }
    58     for(int i=1;i<=cnt1;i++){
    59         if(!t1[i].op){
    60             add(t1[i].id,-t1[i].x);
    61         }
    62     }
    63     for(int i=1;i<=cnt1;i++)t[i+l-1]=t1[i];
    64     for(int i=1;i<=cnt2;i++)t[i+l+cnt1-1]=t2[i];
    65     solve(ql,mid,l,l+cnt1-1);
    66     solve(mid+1,qr,l+cnt1,r);
    67 }
    68 int main(){
    69     scanf("%d%d",&n,&m);
    70     for(int i=1;i<=n;i++){
    71         scanf("%d",&x);
    72         mi=min(mi,x);
    73         mx=max(mx,x);
    74         num[i]=x;
    75         t[++cnt]=task(0,i,1,0,x);
    76     }
    77     for(int i=1;i<=m;i++){
    78         scanf("%s",op);
    79         if(op[0]=='Q'){
    80             scanf("%d%d%d",&x,&y,&k);
    81             t[++cnt]=task(1,++totq,x,y,k);
    82         }else{
    83             scanf("%d%d",&x,&y);
    84             mi=min(mi,y);
    85             mx=max(mx,y);
    86             t[++cnt]=task(0,x,-1,0,num[x]);
    87             t[++cnt]=task(0,x,1,0,y);
    88             num[x]=y;
    89         }
    90     }
    91     solve(mi,mx,1,cnt);
    92     for(int i=1;i<=totq;i++){
    93         printf("%d
    ",ans[i]);
    94     }
    95     return 0;
    96 }

    【BZOJ2738】矩阵乘法

    把第一题改成二维树状数组

     1 #include<algorithm>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cstdio>
     5 #include<cmath>
     6 #include<queue>
     7 #define inf 2147483647
     8 #define eps 1e-9
     9 #define lb(x) (x&-x)
    10 using namespace std;
    11 typedef long long ll;
    12 typedef double db;
    13 struct task{
    14     int id,x,y,xx,yy,v;
    15     task(){}
    16     task(int _id,int _x,int _y,int _xx,int _yy,int _v){
    17         id=_id,x=_x,y=_y,xx=_xx,yy=_yy,v=_v;
    18     }
    19 }t[500001],t1[500001],t2[500001];
    20 int n,m,mi=inf,mx=-inf,x,y,xx,yy,k,cnt=0,ans[500001],tr[501][501];
    21 void add(int x,int y,int v){
    22     for(int i=x;i<=n;i+=lb(i)){
    23         for(int j=y;j<=n;j+=lb(j)){
    24             tr[i][j]+=v;
    25         }
    26     }
    27 }
    28 int query(int x,int y){
    29     int ret=0;
    30     for(int i=x;i;i-=lb(i)){
    31         for(int j=y;j;j-=lb(j)){
    32             ret+=tr[i][j];
    33         }
    34     }
    35     return ret;
    36 }
    37 void solve(int ql,int qr,int l,int r){
    38     if(ql>qr||l>r)return;
    39     if(ql==qr){
    40         for(int i=l;i<=r;i++){
    41             if(t[i].id)ans[t[i].id]=ql;
    42         }
    43         return;
    44     }
    45     int mid=(ql+qr)/2,cnt1=0,cnt2=0;
    46     for(int i=l;i<=r;i++){
    47         if(t[i].id){
    48             int nw=query(t[i].xx,t[i].yy)-query(t[i].x-1,t[i].yy)-query(t[i].xx,t[i].y-1)+query(t[i].x-1,t[i].y-1);
    49             if(nw>=t[i].v)t1[++cnt1]=t[i];
    50             else{
    51                 t[i].v-=nw;
    52                 t2[++cnt2]=t[i];
    53             }
    54         }else{
    55             if(t[i].v<=mid){
    56                 add(t[i].x,t[i].y,1);
    57                 t1[++cnt1]=t[i];
    58             }else t2[++cnt2]=t[i];
    59         }
    60     }
    61     for(int i=1;i<=cnt1;i++){
    62         if(!t1[i].id){
    63             add(t1[i].x,t1[i].y,-1);
    64         }
    65     }
    66     for(int i=1;i<=cnt1;i++)t[i+l-1]=t1[i];
    67     for(int i=1;i<=cnt2;i++)t[i+l+cnt1-1]=t2[i];
    68     solve(ql,mid,l,l+cnt1-1);
    69     solve(mid+1,qr,l+cnt1,r);
    70 }
    71 int main(){
    72     scanf("%d%d",&n,&m);
    73     for(int i=1;i<=n;i++){
    74         for(int j=1;j<=n;j++){
    75             scanf("%d",&x);
    76             t[++cnt]=task(0,i,j,0,0,x);
    77             mi=min(mi,x);
    78             mx=max(mx,x);
    79         }
    80     }
    81     for(int i=1;i<=m;i++){
    82         scanf("%d%d%d%d%d",&x,&y,&xx,&yy,&k);
    83         t[++cnt]=task(i,x,y,xx,yy,k);
    84     }
    85     solve(mi,mx,1,cnt);
    86     for(int i=1;i<=m;i++){
    87         printf("%d
    ",ans[i]);
    88     }
    89     return 0;
    90 }

    【BZOJ2527】【POI2011】Meteors

    环上同一个国家的空间站用链表连起来,每次看当前二分区间内陨石雨下完能否收集到足够的陨石,在最后加上一个量为inf的陨石雨用来判断能否完成,整体二分即可

      1 #include<algorithm>
      2 #include<iostream>
      3 #include<cstring>
      4 #include<cstdio>
      5 #include<cmath>
      6 #include<queue>
      7 #define inf 1000000000000000
      8 #define eps 1e-9
      9 #define lb(x) (x&-x)
     10 using namespace std;
     11 typedef long long ll;
     12 typedef double db;
     13 struct edge{
     14     int v,next;
     15 }a[300001];
     16 struct task{
     17     int l,r;
     18     ll v;
     19     task(){}
     20     task(int _l,int _r,ll _v){
     21         l=_l,r=_r,v=_v;
     22     }
     23 }t[300002];
     24 int n,m,k,x,tot=0,id[300001],ans[300001],head[300001],t1[300001],t2[300001];
     25 ll tr[300001],nw[300001],ad[300001],num[300001];
     26 void add(int u,int v){
     27     a[++tot].v=v;
     28     a[tot].next=head[u];
     29     head[u]=tot;
     30 }
     31 void add(int x,ll v){
     32     for(;x<=m;x+=lb(x)){
     33         tr[x]+=v;
     34     }
     35 }
     36 ll query(int x){
     37     ll ret=0;
     38     for(;x;x-=lb(x)){
     39         ret+=tr[x];
     40     }
     41     return ret;
     42 }
     43 void solve(int ql,int qr,int l,int r){
     44     if(ql>qr||l>r)return;
     45     if(ql==qr){
     46         for(int i=l;i<=r;i++){
     47             ans[id[i]]=ql;
     48         }
     49         return;
     50     }
     51     int mid=(ql+qr)/2,cnt1=0,cnt2=0;
     52     for(int i=ql;i<=mid;i++){
     53         if(t[i].l<=t[i].r){
     54             add(t[i].l,t[i].v);
     55             add(t[i].r+1,-t[i].v);
     56         }else{
     57             add(1,t[i].v);
     58             add(t[i].r+1,-t[i].v);
     59             add(t[i].l,t[i].v);
     60         }
     61     }
     62     for(int i=l;i<=r;i++){
     63         ad[id[i]]=0;
     64         for(int tmp=head[id[i]];tmp!=-1;tmp=a[tmp].next){
     65             int v=a[tmp].v;
     66             ad[id[i]]+=query(v);
     67             if(ad[id[i]]+nw[id[i]]>num[id[i]])break;
     68         }
     69         if(ad[id[i]]+nw[id[i]]>=num[id[i]])t1[++cnt1]=id[i];
     70         else{
     71             nw[id[i]]+=ad[id[i]];
     72             t2[++cnt2]=id[i];
     73         }
     74     }
     75     for(int i=ql;i<=mid;i++){
     76         if(t[i].l<=t[i].r){
     77             add(t[i].l,-t[i].v);
     78             add(t[i].r+1,t[i].v);
     79         }else{
     80             add(1,-t[i].v);
     81             add(t[i].r+1,t[i].v);
     82             add(t[i].l,-t[i].v);
     83         }
     84     }
     85     for(int i=1;i<=cnt1;i++)id[l+i-1]=t1[i];
     86     for(int i=1;i<=cnt2;i++)id[l+cnt1+i-1]=t2[i];
     87     solve(ql,mid,l,l+cnt1-1);
     88     solve(mid+1,qr,l+cnt1,r);
     89 }
     90 int main(){
     91     memset(head,-1,sizeof(head));
     92     scanf("%d%d",&n,&m);
     93     for(int i=1;i<=m;i++){
     94         scanf("%d",&x);
     95         add(x,i);
     96     }
     97     for(int i=1;i<=n;i++){
     98         scanf("%lld",&num[i]);
     99         id[i]=i;
    100     }
    101     scanf("%d",&k);
    102     for(int i=1;i<=k;i++){
    103         scanf("%d%d%lld",&t[i].l,&t[i].r,&t[i].v);
    104     }
    105     t[++k]=task(1,m,inf);
    106     solve(1,k,1,n);
    107     for(int i=1;i<=n;i++){
    108         if(ans[i]<k)printf("%d
    ",ans[i]);
    109         else puts("NIE");
    110     }
    111     return 0;
    112 }

    【BZOJ3110】K大数查询

    其实这是个树套树题……(大雾)树状数组区间修改+区间查询很难搞所以写了个线段树

    ps:双倍经验->【ZJOI2013】KSHKM的学习小组

      1 #include<algorithm>
      2 #include<iostream>
      3 #include<cstring>
      4 #include<cstdio>
      5 #include<cmath>
      6 #include<queue>
      7 #define inf 2147483647
      8 #define eps 1e-9
      9 using namespace std;
     10 typedef long long ll;
     11 typedef double db;
     12 struct node{
     13     int cl;
     14     ll v,laz;
     15 }t[500001];
     16 struct task{
     17     int l,r,id;
     18     ll v,ans;
     19 }q[50001],ad[50001],_q[50001];
     20 int n,m,op,nq=0,nad=0;
     21 bool cmp(task a,task b){
     22     return a.id<b.id;
     23 }
     24 bool cmp1(task a,task b){
     25     return a.v<b.v;
     26 }
     27 void pd(int u,int l,int r){
     28     int mid=(l+r)/2;
     29     if(t[u].cl){
     30         t[u*2].v=t[u*2].laz=t[u*2+1].v=t[u*2+1].laz=0;
     31         t[u*2].cl=t[u*2+1].cl=1;
     32         t[u].cl=0;
     33     }
     34     if(t[u].laz){
     35         t[u*2].laz+=t[u].laz;
     36         t[u*2].v+=(mid-l+1)*t[u].laz;
     37         t[u*2+1].laz+=t[u].laz;
     38         t[u*2+1].v+=(r-mid)*t[u].laz;
     39         t[u].laz=0;
     40     }
     41 }
     42 void updata(int l,int r,int u,int L,int R){
     43     pd(u,l,r);
     44     if(L<=l&&r<=R){
     45         t[u].v+=(r-l+1);
     46         t[u].laz++;
     47         return;
     48     }
     49     int mid=(l+r)/2;
     50     if(L<=mid)updata(l,mid,u*2,L,R);
     51     if(mid<R)updata(mid+1,r,u*2+1,L,R);
     52     t[u].v=t[u*2].v+t[u*2+1].v;
     53 }
     54 ll query(int l,int r,int u,int L,int R){
     55     if(L<=l&&r<=R){
     56         return t[u].v;
     57     }
     58     pd(u,l,r);
     59     int mid=(l+r)/2;
     60     ll ret=0;
     61     if(L<=mid)ret+=query(l,mid,u*2,L,R);
     62     if(mid<R)ret+=query(mid+1,r,u*2+1,L,R);
     63     return ret;
     64 }
     65 void solve(int ql,int qr,int l,int r){
     66     if(ql>qr||l>r)return;
     67     if(ql==qr){
     68         for(int i=l;i<=r;i++){
     69             q[i].ans=ad[ql].v;
     70         }
     71         return;
     72     }
     73     int mid=(ql+qr)/2,cnt1=mid+1,cnt2=l,L=l-1,R=r+1;
     74     t[1].cl=1;
     75     t[1].v=t[1].laz=0;
     76     sort(ad+ql,ad+qr+1,cmp1);
     77     sort(ad+mid+1,ad+qr+1,cmp);
     78     sort(q+l,q+r+1,cmp);
     79     while(cnt2<=r){
     80         if(cnt1<=qr&&ad[cnt1].id<q[cnt2].id){
     81             updata(1,n,1,ad[cnt1].l,ad[cnt1].r);
     82             cnt1++;
     83         }else{
     84             ll nw=query(1,n,1,q[cnt2].l,q[cnt2].r);
     85             if(nw>=q[cnt2].v)_q[--R]=q[cnt2];
     86             else{
     87                 q[cnt2].v-=nw;
     88                 _q[++L]=q[cnt2];
     89             }
     90             cnt2++;
     91         }
     92     }
     93     for(int i=l;i<=r;i++)q[i]=_q[i];
     94     solve(ql,mid,l,L);
     95     solve(mid+1,qr,R,r);
     96 }
     97 int main(){
     98     scanf("%d%d",&n,&m);
     99     for(int i=1;i<=m;i++){
    100         scanf("%d",&op);
    101         if(op==1){
    102             nad++;
    103             scanf("%d%d%lld",&ad[nad].l,&ad[nad].r,&ad[nad].v);
    104             ad[nad].id=i;
    105         }else{
    106             nq++;
    107             scanf("%d%d%lld",&q[nq].l,&q[nq].r,&q[nq].v);
    108             q[nq].id=i;
    109         }
    110     }
    111     solve(1,nad,1,nq);
    112     sort(q+1,q+nq+1,cmp);
    113     for(int i=1;i<=nq;i++){
    114         printf("%lld
    ",q[i].ans);
    115     }
    116     return 0;
    117 }
  • 相关阅读:
    布局-float-margin-padding
    乡镇投票笔记
    Ajax实战
    Form,tagName和nodeName的区别
    Form,选择并转移导航菜单
    如何在ajax请求中设置特殊的RequestHeader
    nginx配置转发详解
    利用循环遍历的方式判断某个对象是否属于这个数组
    几个原生js方法总结
    chrome JS关闭当前页无效问题
  • 原文地址:https://www.cnblogs.com/dcdcbigbig/p/10096063.html
Copyright © 2011-2022 走看看