zoukankan      html  css  js  c++  java
  • 线段树合并&&启发式合并笔记

    这俩东西听起来很高端,实际上很好写,应用也很多~

    线段树合并

    线段树合并,顾名思义,就是建立一棵新的线段树保存原有的两颗线段树的信息。

    考虑如何合并,对于一个结点,如果两颗线段树都有此位置的结点,则直接合并两结点的信息(如维护最大值则取max,维护和则相加),然后递归处理左右子树;

    若只有一个有,直接返回即可。

    这样子做时间复杂度取决于重合节点个数,一次最坏复杂度是$O(nlogn)$,因为满二叉树的结点数是$O(n)$,对每个结点进行处理是$O(logn)$,但是实际应用中需要合并的两颗树重合部分一般较少,所以复杂度可以近似看为$O(logn)$的;

    如果用动态开点线段树的话,一次合并只需要合并一条链,所以时间复杂度是$O(操作数 imes logn)$的

    启发式合并

    启发式合并核心思想就一句话:把小集合的合并到大的里。

    启发式合并思想可以放到很多数据结构里,链表、线段树、甚至平衡树都可以。

    考虑时间复杂度,设总共有$n$个元素,由于每次集合的大小至少翻倍,所以至多会合并$logn$次,总的复杂度就是$O(nlogn)$的(结合线段树合并就是$O(nlog^2n)$的)

    下面举几道例题:

    【BZOJ1483】【HNOI2009】梦幻布丁

    链表+启发式合并,每次换颜色直接合并

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<cmath>
     5 using namespace std;
     6 int n,m,s,x,y,ans=0,a[1000001],lsh[1000001],head[1000001],nxt[1000001],sum[1000001],pre[1000001];
     7 void work(int x,int y){
     8     for(int tmp=head[x];tmp!=-1;tmp=nxt[tmp]){
     9         if(a[tmp+1]==y)ans--;
    10         if(a[tmp-1]==y)ans--;
    11     }
    12     for(int tmp=head[x];tmp!=-1;tmp=nxt[tmp])a[tmp]=y;
    13     nxt[lsh[x]]=head[y];
    14     head[y]=head[x];
    15     sum[y]+=sum[x];
    16     head[x]=-1;
    17     lsh[x]=sum[x]=0;
    18 }
    19 int main(){
    20     memset(sum,0,sizeof(sum));
    21     memset(pre,0,sizeof(pre));
    22     memset(head,-1,sizeof(head));
    23     scanf("%d%d",&n,&m);
    24     for(int i=1;i<=n;i++){
    25         scanf("%d",&a[i]);
    26         pre[a[i]]=a[i];
    27         if(a[i]!=a[i-1])ans++;
    28         if(head[a[i]]==-1)lsh[a[i]]=i;
    29         sum[a[i]]++;
    30         nxt[i]=head[a[i]];
    31         head[a[i]]=i;
    32     }
    33     for(int i=1;i<=m;i++){
    34         scanf("%d",&s);
    35         if(s==2)printf("%d
    ",ans);
    36         else{
    37             scanf("%d%d",&x,&y);
    38             if(x==y)continue;
    39             if(sum[pre[x]]>sum[pre[y]])swap(pre[x],pre[y]);
    40             x=pre[x],y=pre[y];
    41             if(!sum[x])continue;
    42             work(x,y);
    43         }
    44     }
    45     return 0;
    46 }

    【BZOJ3123】【SDOI2013】森林

    主席树+启发式合并

      1 #include<algorithm>
      2 #include<iostream>
      3 #include<cstring>
      4 #include<cstdio>
      5 #include<cmath>
      6 #define N 1000000000
      7 using namespace std;
      8 typedef long long ll;
      9 struct edge{
     10     int v,next;
     11 }a[2000001];
     12 int DYZ_HAS_CHANCE,n,m,t,u,v,w,ans=0,tot=0,cnt=0,rt[1000001],ls[5000001],rs[5000001],siz[5000001],sum[1000001],f[1000001],num[1000001],fa[1000001][20],dep[1000001],head[1000001];
     13 bool used[1000001];
     14 char s[10];
     15 int ff(int u){
     16     return f[u]==u?u:f[u]=ff(f[u]);
     17 }
     18 void add(int u,int v){
     19     a[++tot].v=v;
     20     a[tot].next=head[u];
     21     head[u]=tot;
     22 }
     23 int lca(int u,int v){
     24     if(dep[u]<dep[v])swap(u,v);
     25     int l=dep[u]-dep[v];
     26     for(int i=19;i>=0;i--){
     27         if((1<<i)&l)u=fa[u][i];
     28     }
     29     if(u==v)return u;
     30     for(int i=19;i>=0;i--){
     31         if(fa[u][i]!=fa[v][i]){
     32             u=fa[u][i],v=fa[v][i];
     33         }
     34     }
     35     return fa[u][0];
     36 }
     37 void updata(int k,int &now,int l,int r,int v){
     38     if(!now)now=++cnt;
     39     siz[now]=siz[k]+1;
     40     if(l==r)return;
     41     int mid=(l+r)/2;
     42     if(v<=mid)rs[now]=rs[k],updata(ls[k],ls[now],l,mid,v);
     43     else ls[now]=ls[k],updata(rs[k],rs[now],mid+1,r,v);
     44 }
     45 int query(int a1,int a2,int a3,int a4,int l,int r,int v){
     46     if(l==r)return l;
     47     int mid=(l+r)/2,ret=siz[ls[a1]]+siz[ls[a2]]-siz[ls[a3]]-siz[ls[a4]];
     48     if(v<=ret)return query(ls[a1],ls[a2],ls[a3],ls[a4],l,mid,v);
     49     else return query(rs[a1],rs[a2],rs[a3],rs[a4],mid+1,r,v-ret);       
     50 }
     51 void dfs(int u,int f){
     52     used[u]=true;
     53     dep[u]=dep[f]+1;
     54     fa[u][0]=f;
     55     for(int i=1;i<=19;i++)fa[u][i]=fa[fa[u][i-1]][i-1];
     56     updata(rt[f],rt[u],0,N,num[u]);
     57     for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
     58         int v=a[tmp].v;
     59         if(v!=f)dfs(v,u);
     60     }
     61 }
     62 void merge(int u,int v){
     63     int u1=ff(u),v1=ff(v);
     64     f[u1]=v1;
     65     sum[v1]+=sum[u1];
     66 }
     67 int main(){
     68     memset(head,-1,sizeof(head));
     69     memset(used,0,sizeof(used));
     70     memset(rt,0,sizeof(rt));
     71     scanf("%d",&DYZ_HAS_CHANCE);
     72     scanf("%d%d%d",&n,&m,&t);
     73     for(int i=1;i<=n;i++){
     74         scanf("%d",&num[i]);
     75         f[i]=i;
     76         sum[i]=1;
     77     }
     78     for(int i=1;i<=m;i++){
     79         scanf("%d%d",&u,&v);
     80         add(u,v);
     81         add(v,u);
     82         merge(u,v);
     83     }
     84     for(int i=1;i<=n;i++){
     85         if(!used[i])dfs(i,0);
     86     }
     87     for(int i=1;i<=t;i++){
     88         scanf("%s",s);
     89         if(s[0]=='Q'){
     90             scanf("%d%d%d",&u,&v,&w);
     91             u^=ans;
     92             v^=ans;
     93             w^=ans;
     94             int now=lca(u,v);
     95             printf("%d
    ",ans=query(rt[u],rt[v],rt[now],rt[fa[now][0]],0,N,w));
     96         }else{
     97             scanf("%d%d",&u,&v);
     98             u^=ans;
     99             v^=ans;
    100             int u1=ff(u),v1=ff(v);
    101             if(sum[u1]>sum[v1])swap(u,v);
    102             add(u,v);
    103             add(v,u);
    104             merge(u,v);
    105             dfs(u,v);
    106         }
    107     }
    108     return 0;
    109 }

    【BZOJ3545】【ONTAK2010】Peaks

    离线,按照困难度从小到大加边,用线段树维护每个联通块,每次合并联通块即可

     1 #include<algorithm>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cstdio>
     5 #include<cmath>
     6 using namespace std;
     7 struct task{
     8     int a,b,c,id,ok;
     9 }a[1000001];
    10 struct treenode{
    11     int v,ls,rs;
    12 }t[5000001];
    13 int n,m,q,tot=0,num[100001],_num[100001],fa[100001],rts[100001],ans[500001];
    14 bool cmp(task a,task b){
    15     return a.c==b.c?a.ok<b.ok:a.c<b.c;
    16 }
    17 int ff(int u){
    18     return u==fa[u]?u:fa[u]=ff(fa[u]);
    19 }
    20 void updata(int &u,int l,int r,int v){
    21     if(!u)u=++tot;
    22     t[u].v=1;
    23     if(l==r)return;
    24     int mid=(l+r)/2;
    25     if(v<=mid)updata(t[u].ls,l,mid,v);
    26     else updata(t[u].rs,mid+1,r,v);
    27 }
    28 int query(int u,int l,int r,int p){
    29     if(l==r)return l;
    30     int mid=(l+r)/2;
    31     if(p<=t[t[u].ls].v)return query(t[u].ls,l,mid,p);
    32     else return query(t[u].rs,mid+1,r,p-t[t[u].ls].v);
    33 }
    34 int merge(int u,int v){
    35     if(!u||!v)return u|v;
    36     if(!t[u].ls&&!t[u].rs){
    37         t[u].v+=t[v].v;
    38         return u;
    39     }
    40     t[u].ls=merge(t[u].ls,t[v].ls);
    41     t[u].rs=merge(t[u].rs,t[v].rs);
    42     t[u].v=t[t[u].ls].v+t[t[u].rs].v;
    43     return u;
    44 }
    45 int main(){
    46     scanf("%d%d%d",&n,&m,&q);
    47     for(int i=1;i<=n;i++){
    48         scanf("%d",&num[i]);
    49         _num[i]=num[i];
    50         fa[i]=i;
    51     }
    52     sort(_num+1,_num+n+1);
    53     for(int i=1;i<=n;i++){
    54         num[i]=lower_bound(_num+1,_num+n+1,num[i])-_num;
    55     }
    56     for(int i=1;i<=m;i++){
    57         scanf("%d%d%d",&a[i].a,&a[i].b,&a[i].c);
    58         a[i].ok=0;
    59     }
    60     for(int i=m+1;i<=m+q;i++){
    61         scanf("%d%d%d",&a[i].a,&a[i].c,&a[i].b);
    62         a[i].ok=1;
    63         a[i].id=i-m;
    64     }
    65     sort(a+1,a+m+q+1,cmp);
    66     for(int i=1;i<=n;i++)updata(rts[i],1,n,num[i]);
    67     for(int i=1;i<=m+q;i++){
    68         if(a[i].ok==0){
    69             int u=ff(a[i].a),v=ff(a[i].b);
    70             if(u!=v){
    71                 fa[u]=v;
    72                 rts[v]=merge(rts[u],rts[v]);
    73             }
    74         }else{
    75              int u=ff(a[i].a);
    76              if(t[rts[u]].v<a[i].b)ans[a[i].id]=-1;
    77              else ans[a[i].id]=_num[query(rts[u],1,n,t[rts[u]].v-a[i].b+1)];
    78         }
    79     }
    80     for(int i=1;i<=q;i++)printf("%d
    ",ans[i]);
    81     return 0;
    82 }

    【BZOJ2212】【POI2011】Tree Rotation

    直接从下往上线段树合并即可

     1 #include<algorithm>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cstdio>
     5 #include<cmath>
     6 using namespace std;
     7 typedef long long ll;
     8 struct treenode{
     9     ll v;
    10     int ls,rs;
    11 }t[6000001];
    12 int n,tot=0,cnt=1,num[2000001],ls[2000001],rs[2000001],rts[2000001];
    13 ll ans=0,ans1,ans2;
    14 void read(int u){
    15     scanf("%d",&num[u]);
    16     if(!num[u]){
    17         read(ls[u]=++cnt);
    18         read(rs[u]=++cnt);
    19     }
    20 }
    21 void updata(int &u,int l,int r,int v){
    22     if(!u)u=++tot;
    23     if(l==r){
    24         t[u].v=1;
    25         return;
    26     }
    27     int mid=(l+r)/2;
    28     if(v<=mid)updata(t[u].ls,l,mid,v);
    29     else updata(t[u].rs,mid+1,r,v);
    30     t[u].v=t[t[u].ls].v+t[t[u].rs].v;
    31 }
    32 int merge(int u,int v){
    33     if(!u||!v)return u|v;
    34     ans1+=(ll)t[t[u].rs].v*t[t[v].ls].v;
    35     ans2+=(ll)t[t[u].ls].v*t[t[v].rs].v;
    36     t[u].ls=merge(t[u].ls,t[v].ls);
    37     t[u].rs=merge(t[u].rs,t[v].rs);
    38     t[u].v=t[t[u].ls].v+t[t[u].rs].v;
    39     return u;
    40 }
    41 void dfs(int u){
    42     if(!u)return;
    43     dfs(ls[u]);
    44     dfs(rs[u]);
    45     if(!num[u]){
    46         ans1=ans2=0;
    47         rts[u]=merge(rts[ls[u]],rts[rs[u]]);
    48         ans+=min(ans1,ans2);
    49     }
    50 }
    51 int main(){
    52     scanf("%d",&n);
    53     read(1);
    54     for(int i=1;i<=cnt;i++){
    55         if(num[i])updata(rts[i],1,n,num[i]);
    56     }
    57     dfs(1);
    58     printf("%lld",ans);
    59     return 0;
    60 }

    现在搞专题沉迷摸鱼,一天平均只有两道题,颓废力max

  • 相关阅读:
    【转】JSch
    【转】JSch
    【转】class卸载、热替换和Tomcat的热部署的分析
    关于Tomcat自动加载更新class的小技巧
    MySQL中order by中关于NULL值的排序问题
    MySQL触发器使用详解
    QuartZ Cron表达式
    JDBC的URL设置allowMultiQueries的原因
    CRT:C运行库简介
    IntelliJ IDEA安装AngularJS插件
  • 原文地址:https://www.cnblogs.com/dcdcbigbig/p/9304244.html
Copyright © 2011-2022 走看看