zoukankan      html  css  js  c++  java
  • 二进制分组

    二进制分组思想很简单,就是把下标拆成几个2的次幂的和,对每个2的次幂维护答案,复杂度是暴力重构一组的复杂度乘log(如果可以归并可能会少个log)。

    这里其实想整理下一些修改独立的数据结构题的套路。

    离线算法:

      (1) 只有插入:CDQ分治。

      (2) 有删除:

        支持删除操作:CDQ分治。

        不支持删除但支持按插入反序撤销:线段树分治。

        不支持删除与撤销:时间倒流。

      (3)每次询问的是某个修改区间内的所有修改都生效时的答案:分治+前后缀和。

      (4)答案可二分、修改的贡献具有交换律、结合律、可加性:整体二分。

      (5)每次询问的是一个区间:莫队、回滚莫队。

    在线算法: (1) 随机。 (2) 二进制分组。

    二进制分组题表:

    [BZOJ4140]共点圆加强版

    论文题。化下式子发现是一个半平面,于是问题变为在线插入点并询问某个半平面内是否有点。维护点集的凸包,每次合并两组的时候暴力重构即可。

     1 #include<cstdio>
     2 #include<vector>
     3 #include<algorithm>
     4 #define pb push_back
     5 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     6 using namespace std;
     7 
     8 const int N=500100;
     9 double x,y;
    10 int n,ans,top,op;
    11 struct P{ double x,y; }a[N];
    12 bool operator <(const P &a,const P &b){ return a.x==b.x ? a.y<b.y : a.x<b.x; }
    13 
    14 double sl(P a,P b){
    15     if (a.x==b.x) return a.y>b.y ? 1e18 : -1e18;
    16     return (a.y-b.y)/(a.x-b.x);
    17 }
    18 
    19 struct Gr{
    20     vector<P>p,q; int tot,top;
    21     void ins(P x){ tot++; p.pb(x); }
    22     void clear(){ p.clear(); q.clear(); tot=top=0; }
    23 
    24     void build(){
    25         sort(p.begin(),p.end()); top=1; q.clear(); q.pb(p[0]);
    26         rep(i,1,tot-1){
    27             while (top>1 && sl(q[top-1],q[top-2])-sl(q[top-1],p[i])>=0) top--,q.pop_back();
    28             q.pb(p[i]); top++;
    29         }
    30     }
    31 
    32     bool que(double x,double y){
    33         double k=-x/y; int l=1,r=top-1,res=0;
    34         while (l<=r){
    35             int mid=(l+r)>>1;
    36             if (sl(q[mid],q[mid-1])<=k) l=mid+1,res=mid; else r=mid-1;
    37         }
    38         return 2*x*q[res].x+2*y*q[res].y>=x*x+y*y;
    39     }
    40 }B[50];
    41 
    42 void ins(double x,double y){
    43     B[++top].ins((P){x,y});
    44     while (top>1 && B[top].tot==B[top-1].tot){
    45         rep(i,0,B[top].tot-1) B[top-1].ins(B[top].p[i]);
    46         B[top--].clear();
    47     }
    48     B[top].build();
    49 }
    50 
    51 bool que(double x,double y){
    52     if (!top) return 0;
    53     rep(i,1,top) if (!B[i].que(x,y)) return 0;
    54     return 1;
    55 }
    56 
    57 int main(){
    58     scanf("%d",&n);
    59     rep(i,1,n){
    60         scanf("%d%lf%lf",&op,&x,&y); x+=ans; y+=ans;
    61         if (!op) ins(x,y);
    62         else if (que(x,y)) ans++,puts("Yes"); else puts("No");
    63     }
    64     return 0;
    65 }
    BZOJ4140

    [BZOJ2989]数列

    树套树或者CDQ分治或者3D-Tree模板题,大家都用它来练二进制分组。

    对插入时间二进制分组,然后就是一个二维数点问题,两组的合并最好用归并。

    主席树是一个DAG,要注意删除与垃圾回收的实现。

     1 #include<cstdio>
     2 #include<vector>
     3 #include<algorithm>
     4 #define mp make_pair
     5 #define pb push_back
     6 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     7 using namespace std;
     8 
     9 const int N=200010,M=200000,K=65000,inf=1e9;
    10 char op[10];
    11 bool vis[N<<5];
    12 int n,Q,top,tot,nd,a[N],rt[20][N],ls[N<<5],rs[N<<5],v[N<<5],stk[N<<5];
    13 vector<pair<int,int> >t,ve[20];
    14 
    15 int get(){
    16     if (top) { vis[stk[top]]=1; return stk[top--]; }
    17         else{ vis[++nd]=1; return nd; }
    18 }
    19 
    20 int que(int x,int y,int L,int R,int l,int r){
    21     if (L==l && r==R) return v[y]-v[x];
    22     int mid=(L+R)>>1;
    23     if (r<=mid) return que(ls[x],ls[y],L,mid,l,r);
    24     else if (l>mid) return que(rs[x],rs[y],mid+1,R,l,r);
    25         else return que(ls[x],ls[y],L,mid,l,mid)+que(rs[x],rs[y],mid+1,R,mid+1,r);
    26 }
    27 
    28 void mdf(int y,int &x,int L,int R,int k){
    29     x=get(); ls[x]=ls[y]; rs[x]=rs[y]; v[x]=v[y]+1;
    30     if (L==R) return;
    31     int mid=(L+R)>>1;
    32     if (k<=mid) mdf(ls[y],ls[x],L,mid,k);
    33         else mdf(rs[y],rs[x],mid+1,R,k);
    34 }
    35 
    36 void del(int &x){
    37     if (!vis[x]) return;
    38     stk[++top]=x; vis[x]=0;
    39     del(ls[x]); del(rs[x]); v[x]=0; x=0;
    40 }
    41 
    42 void ins(int x,int y){
    43     ve[++tot].pb(mp(x,y)); mdf(0,rt[tot][1],1,M,y);
    44     while (tot>1 && ve[tot-1].size()==ve[tot].size()){
    45         int t1=0,t2=0,ed=ve[tot].size(); t.clear();
    46         rep(i,1,ed) del(rt[tot-1][i]);
    47         rep(i,1,ed) del(rt[tot][i]);
    48         while (t1<(int)ve[tot-1].size() || t2<(int)ve[tot].size()){
    49             if (t1<(int)ve[tot-1].size() && (t2==(int)ve[tot].size() || ve[tot-1][t1]<ve[tot][t2])) t.pb(ve[tot-1][t1++]);
    50                 else t.pb(ve[tot][t2++]);
    51             mdf(rt[tot-1][t1+t2-1],rt[tot-1][t1+t2],1,M,t[t1+t2-1].second);
    52         }
    53         ve[tot-1]=t; ve[tot].clear(); tot--;
    54     }
    55 }
    56 
    57 int que(int x,int y,int d){
    58     int res=0;
    59     rep(i,1,tot){
    60         int k1=lower_bound(ve[i].begin(),ve[i].end(),mp(x+d,inf))-ve[i].begin();
    61         int k2=lower_bound(ve[i].begin(),ve[i].end(),mp(x-d,0))-ve[i].begin();
    62         res+=que(rt[i][k2],rt[i][k1],1,M,max(1,y-d),min(y+d,M));
    63     }
    64     return res;
    65 }
    66 
    67 int main(){
    68     freopen("bzoj2989.in","r",stdin);
    69     freopen("bzoj2989.out","w",stdout);
    70     scanf("%d%d",&n,&Q);
    71     rep(i,1,n) scanf("%d",&a[i]),ins(a[i]+i,a[i]-i+K);
    72     while (Q--){
    73         scanf("%s",op); int x,y; scanf("%d%d",&x,&y);
    74         if (op[0]=='Q') printf("%d
    ",que(a[x]+x,a[x]-x+K,y));
    75             else a[x]=y,ins(a[x]+x,a[x]-x+K);
    76     }
    77     return 0;
    78 }
    BZOJ2989

    [CF710F]String Set Queries

    没有插入删除就是AC自动机模板题。发现删除操作就是另维护一个AC自动机计算已删除的串的贡献,于是只用考虑插入。

    CDQ分治或二进制分组均可。AC自动机是有向图(还可能存在自环),所以同样要注意删除和垃圾回收的实现。

    平时只建一个AC自动机时,根是0,所以fail和son有时会不赋值。建多棵的时候就要注意把所有为0的指针都要指向rt。

      1 #include<cstdio>
      2 #include<string>
      3 #include<vector>
      4 #include<iostream>
      5 #include<algorithm>
      6 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
      7 #define pb push_back
      8 using namespace std;
      9 
     10 const int N=300100;
     11 string s;
     12 int m,op,top,nd,top1,top2,son[N][27],fail[N],v[N],stk[N],q[N];
     13 
     14 int get(){ return top ? stk[top--] : ++nd; }
     15 
     16 void ins(int x,string s){
     17     int len=s.length();
     18     rep(i,0,len-1){
     19         if (!son[x][s[i]-'a']) son[x][s[i]-'a']=get();
     20         x=son[x][s[i]-'a'];
     21     }
     22     v[x]++;
     23 }
     24 
     25 void del(int x){
     26     if (!fail[x]) return;
     27     fail[x]=v[x]=0; stk[++top]=x;
     28     rep(i,0,25) del(son[x][i]),son[x][i]=0;
     29 }
     30 
     31 struct Gr{
     32     vector<string>p; int tot,rt;
     33     void ins(string s){ p.pb(s); tot++; }
     34     void clear(){ del(rt); rt=get(); p.clear(); tot=0; }
     35     void build(){
     36         del(rt); rt=get();
     37         rep(i,0,tot-1) ::ins(rt,p[i]);
     38         int st=0,ed=0; fail[rt]=rt;
     39         rep(i,0,25) if (son[rt][i]) q[++ed]=son[rt][i],fail[son[rt][i]]=rt;
     40         while (st<ed){
     41             int x=q[++st];
     42             rep(i,0,25){
     43                 int c=son[fail[x]][i];
     44                 if (son[x][i]) fail[son[x][i]]=c?c:rt,q[++ed]=son[x][i];
     45                     else son[x][i]=c?c:rt;
     46             }
     47             v[x]+=v[fail[x]];
     48         }
     49     }
     50     int que(string s){
     51         int res=0,x=rt,len=s.length();
     52         rep(i,0,len-1){
     53             int c=s[i]-'a';
     54             if (son[x][c]) x=son[x][c];
     55             else{
     56                 int p=fail[x];
     57                 while (p!=rt && !son[p][c]) p=fail[p];
     58                 if (son[p][c]) x=son[p][c];
     59             }
     60             res+=v[x];
     61         }
     62         return res;
     63     }
     64 }A[20],B[20];
     65 
     66 void ins(string s){
     67     top1++; A[top1].clear(); A[top1].ins(s);
     68     while (top1>1 && A[top1].tot==A[top1-1].tot){
     69         rep(i,0,A[top1].tot-1) A[top1-1].ins(A[top1].p[i]);
     70         A[top1--].clear();
     71     }
     72     A[top1].build();
     73 }
     74 
     75 void del(string s){
     76     top2++; B[top2].clear(); B[top2].ins(s);
     77     while (top2>1 && B[top2].tot==B[top2-1].tot){
     78         rep(i,0,B[top2].tot-1) B[top2-1].ins(B[top2].p[i]);
     79         B[top2--].clear();
     80     }
     81     B[top2].build();
     82 }
     83 
     84 int que(string s){
     85     int res=0;
     86     rep(i,1,top1) res+=A[i].que(s);
     87     rep(i,1,top2) res-=B[i].que(s);
     88     return res;
     89 }
     90 
     91 int main(){
     92     freopen("710F.in","r",stdin);
     93     freopen("710F.out","w",stdout);
     94     for (scanf("%d",&m); m--; ){
     95         cin>>op>>s;
     96         if (op==1) ins(s);
     97         if (op==2) del(s);
     98         if (op==3) cout<<que(s)<<endl;
     99     }
    100     return 0;
    101 }
    CF710F
  • 相关阅读:
    怎样才能算是在技术上活跃的小公司
    jquery幻灯片--渐变
    cpm效果介绍
    我依然热爱编程
    项目开发经验终结2015/4/7
    windows上putty访问ubuntu
    ubuntu安装openssh-server
    今天犯了一个低级错误
    linux 搭建lamp环境
    能用存储过程的DBHelper类
  • 原文地址:https://www.cnblogs.com/HocRiser/p/10734655.html
Copyright © 2011-2022 走看看