[Study notes] together tree analysis

definition

For convenience, the following definitions are to a \ (n-\) Order arrayed

  • A range definition segment $ ran [l, r] = [min a_i, max a_i] (l \ le i \ le r) $, for a permutation \ (ran [l, r] \ ge r-l + 1 \)

    1 is a defined segment of the continuous, if and \ (| RAN [L, R & lt] | = L + 1-R & lt \) , apparently $ \ varnothing, [1, n ], [i, i] $ is continuous

    Property 1:

    For two consecutive segments, they must have a continuous cross section

    For continuous two post sections, and they must be either one continuous segment

    For post \ (A, B \) , you need only consider the $ A \ cap B, A \ cup B $ , so what this means?

  • 2 successive segments define a primitive is consecutive segments, if and only if the absence of continuous segments meet and it is not contained in the intersection relationship

    Such a number of successive segments can be viewed as nodes \ (O (n) \) tree

  • 3 definitions defined above tree formed by consecutive segments of primitive array analysis tree engagement

    Property 2:

    Son together tree node analysis must meet one of the following properties:

    Son node consecutive segments as a whole, forming a son sequence selected from the interval period is the son

    1. there is no non-trivial one son node interval are grouped into successive segments, referred to as analysis points

    2. Any interval son nodes are continuous sections, known as co-point

    Proof:
    For a non-trivial (or not all sons of the individual section) is a continuous section, it is not primitive, then there must be a continuous segment and further it intersects the three intersecting portion after the property is noted in a relatively sequence, and then consider them and this continues will be able to fully cover the entire range of the son of a number of sections, they are relatively ordered, if the cell is not among these ordinary, then such an operation, and finally get his son intervals are are relatively ordered, it is to satisfy the non-analyzed and properties i.e.

    Property 3:

    Analysis of all the trees can form together successive sections, and all successive segments in the analysis tree must fit the following two forms:

    1. successive segments constituting the tree node

    2. The successive segments nontrivial son engagement point interval configuration

    Proof:
    According to the nature of 1, all the successive sections are inseparably certain node in the tree, consider a continuous segment of \ (v_1, v_2, \ cdots , v_k (k> 1) \) configuration and that find \ (V_1 \) to \ (v_K \) of lca, since v1 to vk are continuous stitching and the son lca all primitive, it will be able to direct his son to replace this interval lca

structure

  • basic method:

    Consider increment, assumed do i, has been \ (1-> i-1 \ ) bit combined forest analysis, analysis with a stack maintain this engagement Forest

    Incremental use the following method:

    Setting a current point \ (now \) , initially \ ([I, I] \) , is considered point stack top

    1. If the top is the combined points, and now it can be used as the last son, it will now be set to top last son, a new pop-up top now, repeat the process

    2. or back to find the top of the stack from the top of the least number of points can start and now make up the continuous segment, they pop, add a new point to these points and now even the original side, will now set a new point, repeat this process

    2 until the stack is empty or not found

    Description: // here seem to think about it a little less strict so into explains. . .

    Has popped some point anyway increment is primitive, first of all it is now certain is primitive

    And the successive segments after it intersects with its parent take a certain cross section can be obtained now and it intersects, i.e., it is not now the primitive

    Add New successive segments, consecutive segments primitive to be considered must be formed and a portion of the top of the stack forests

    Must now attempt to characterize \ ([1, i] \ ) primitive continuous sections clearly \ ([i, i] \ ) is the, now set to the next now '

    If you now 'does not necessarily primitive existence and what it intersects, considering where it's possible to r

    Because now is so primitive, this segment will not be continuous r in now

    This must be a continuous period before the incremental existing apparently now 'does not intersect

  • Complexity analysis:
    1 is \ (O (n) \) , if 2 are merged out point is \ (O (n) \) , but if in the end can not be merged, complexity may be degraded to \ (O (^ n-2) \) , it is necessary a \ (L_i \) represented by \ (I \) farthest left end point of the continuous fragment of the right end point, to break it exceeds \ (O (n) \ ) the

  • How to get \ (L \) :

  • Maintenance of the dynamic segment tree r \ (max (l, r) -min (l, r) - (rl) \) takes the minimum value 0 to the foremost l

  • max and min can be maintained stack monotone

    LCA ppt in the O (n) sense approach is not very useful addition to the achievements, there is no written

example

  • n-order arrangement, comprising interrogation \ ([l_i, r_i] \ ) is the minimum consecutive segments

  • After the construction of a combined analysis of the nature of the tree to find lca 3, if it is then the answer is that it analyzes point range, otherwise it is a direct son of the son of the interval l, r direction formed

  • code

    #include<bits/stdc++.h>
    #define il inline 
    #define rg register 
    using namespace std;
    const int N=200010;
    int n,m,a[N],st1[N],st2[N],tp1,tp2,rt,L[N],R[N],M[N],id[N],cnt,typ[N],bin[20],st[N],tp;
    
    il int min(int x,int y){if(x<y)return x;return y;}
    il int max(int x,int y){if(x>y)return x;return y;}
    char gc(){
      static char*p1,*p2,s[1000000];
      if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin);
      return(p1==p2)?EOF:*p1++;
    }
    int rd(){
      int x=0;char c=gc();
      while(c<'0'||c>'9')c=gc();
      while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+c-'0',c=gc();
      return x;
    }
    char ps[1000000],*pp=ps;
    void flush(){fwrite(ps,1,pp-ps,stdout);pp=ps;}
    void push(char x){if(pp==ps+1000000)flush();*pp++=x;}
    void write(int l,int r){
      static int sta[N],top;
      if(!l)push('0');else{
      while(l)sta[++top]=l%10,l/=10;
      while(top)push(sta[top--]^'0');}
      push(' ');
      if(!r)push('0');else{
      while(r)sta[++top]=r%10,r/=10;
      while(top)push(sta[top--]^'0');}
      push('\n');
    }
    
    struct RMQ{
      int lg[N],mn[N][17],mx[N][17];
      void chkmn(int&x,int y){if(x>y)x=y;}
      void chkmx(int&x,int y){if(x<y)x=y;}
      void build(){
          for(int i=bin[0]=1;i<20;++i)bin[i]=bin[i-1]<<1;
          for(int i=2;i<=n;++i)lg[i]=lg[i>>1]+1;
          for(int i=1;i<=n;++i)mn[i][0]=mx[i][0]=a[i];
          for(int i=1;i<17;++i)
          for(int j=1;j+bin[i]-1<=n;++j)
              mn[j][i]=min(mn[j][i-1],mn[j+bin[i-1]][i-1]),
              mx[j][i]=max(mx[j][i-1],mx[j+bin[i-1]][i-1]);
      }
      int ask_mn(int l,int r){
          int t=lg[r-l+1];
          return min(mn[l][t],mn[r-bin[t]+1][t]);
      }
      int ask_mx(int l,int r){
          int t=lg[r-l+1];
          return max(mx[l][t],mx[r-bin[t]+1][t]);
      }
    }D;
    //维护L_i
    struct SEG{
      #define ls (k<<1)
      #define rs (k<<1|1)
      int mn[N<<1],ly[N<<1];
      void pushup(int k){mn[k]=min(mn[ls],mn[rs]);}
      void mfy(int k,int v){mn[k]+=v,ly[k]+=v;}
      void pushdown(int k){if(ly[k])mfy(ls,ly[k]),mfy(rs,ly[k]),ly[k]=0;}
      void update(int k,int l,int r,int x,int y,int v){
          if(l==x&&r==y){mfy(k,v);return;}
          pushdown(k);
          int mid=(l+r)>>1;
          if(y<=mid)update(ls,l,mid,x,y,v);
          else if(x>mid)update(rs,mid+1,r,x,y,v);
          else update(ls,l,mid,x,mid,v),update(rs,mid+1,r,mid+1,y,v);
          pushup(k);
      }
      int query(int k,int l,int r){
          if(l==r)return l;
          pushdown(k);
          int mid=(l+r)>>1;
          if(!mn[ls])return query(ls,l,mid);
          else return query(rs,mid+1,r);
      }
    }T;
    
    int o=1,hd[N],dep[N],fa[N][18];
    struct Edge{int v,nt;}E[N<<1];
    void add(int u,int v){
      E[o]=(Edge){v,hd[u]};hd[u]=o++;
    //    printf("%d %d\n",u,v);
    }
    void dfs(int u){
      for(int i=1;bin[i]<=dep[u];++i)fa[u][i]=fa[fa[u][i-1]][i-1];
      for(int i=hd[u];i;i=E[i].nt){
          int v=E[i].v;
          dep[v]=dep[u]+1;
          fa[v][0]=u;
          dfs(v);
      }
    }
    int go(int u,int d){for(int i=0;i<18&&d;++i)if(bin[i]&d)d^=bin[i],u=fa[u][i];return u;}
    int lca(int u,int v){
      if(dep[u]<dep[v])swap(u,v);
      u=go(u,dep[u]-dep[v]);
      if(u==v)return u;
      for(int i=17;~i;--i)if(fa[u][i]!=fa[v][i])u=fa[u][i],v=fa[v][i];
      return fa[u][0];
    }
    bool judge(int l,int r){return D.ask_mx(l,r)-D.ask_mn(l,r)==r-l;}
    //建树
    void build(){
      for(int i=1;i<=n;++i){
          //单调栈
          while(tp1&&a[i]<=a[st1[tp1]])
              T.update(1,1,n,st1[tp1-1]+1,st1[tp1],a[st1[tp1]]),tp1--;
          while(tp2&&a[i]>=a[st2[tp2]])
              T.update(1,1,n,st2[tp2-1]+1,st2[tp2],-a[st2[tp2]]),tp2--;
          T.update(1,1,n,st1[tp1]+1,i,-a[i]);st1[++tp1]=i;
          T.update(1,1,n,st2[tp2]+1,i,a[i]);st2[++tp2]=i;
    
          id[i]=++cnt;L[cnt]=R[cnt]=i;
          int le=T.query(1,1,n),now=cnt;
          while(tp&&L[st[tp]]>=le){
              if(typ[st[tp]]&&judge(M[st[tp]],i)){
                  R[st[tp]]=i;
                  add(st[tp],now);
                  now=st[tp--];
              }else if(judge(L[st[tp]],i)){
                  typ[++cnt]=1;//合点一定是被这样建出来的
                  L[cnt]=L[st[tp]];R[cnt]=i;M[cnt]=L[now];
                  add(cnt,st[tp--]);add(cnt,now);
                  now=cnt;
              }else{
                  add(++cnt,now);
                  do add(cnt,st[tp--]);while(tp&&!judge(L[st[tp]],i));
                  L[cnt]=L[st[tp]];R[cnt]=i;add(cnt,st[tp--]);
                  now=cnt;
              }
          }
          st[++tp]=now;
    
          T.update(1,1,n,1,i,-1);
      }
    
      rt=st[1]; 
    }
    void query(int r,int l){
      int x=id[l],y=id[r];
      int z=lca(x,y);
      if(typ[z]&1)
          l=L[go(x,dep[x]-dep[z]-1)],
          r=R[go(y,dep[y]-dep[z]-1)];
      else l=L[z],r=R[z];
      write(l,r);
    }//分lca为析或和,这里把叶子看成析的
    
    int main(){
      freopen("c.in","r",stdin);
      freopen("c.out","w",stdout);
      n=rd();for(int i=1;i<=n;++i)a[i]=rd();
      D.build();
      build();
      dfs(rt);
      m=rd();for(int i=1;i<=m;++i)query(rd(),rd());
      return flush(),0;
    }
    //20190612
    //析合树

Guess you like

Origin www.cnblogs.com/Paul-Guderian/p/11020708.html
Recommended