zoukankan      html  css  js  c++  java
  • 第k小元素学习记录

    从第K元素看数据结构>>http://www.cppblog.com/820986942/archive/2011/05/23/146991.html 

    View Code
      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 
      5 using namespace std;
      6 
      7 #define ls rt<<1
      8 #define rs rt<<1|1
      9 #define lson l,m,ls
     10 #define rson m+1,r,rs
     11 #define mid (l+r)>>1
     12 
     13 #define MAXN 200010
     14 
     15 int sum[MAXN<<2];//记录有几个点在节点的范围内
     16 int rank[MAXN],fa[MAXN];//rank表示集合的大小,fa表示根
     17 int n;
     18 
     19 void init(int n)
     20 {
     21     for(int i=0;i<=n;i++)
     22     {
     23         rank[i]=1;
     24         fa[i]=i;
     25     }
     26 }
     27 
     28 int find(int x)
     29 {
     30     if(x != fa[x])
     31         fa[x]=find(fa[x]);
     32     return fa[x];
     33 }
     34 
     35 void build(int l,int r,int rt)
     36 {
     37     if(l==1)//开始时每个集合的大小都为1故都在区间[1,r]内
     38         sum[rt]=n;
     39     else
     40         sum[rt]=0;
     41     if(l==r) return ;
     42     int m=mid;
     43     build(lson);
     44     build(rson);
     45 }
     46 
     47 void update(bool flag,int val,int l,int r,int rt)
     48 {
     49     if(!flag)//flag见main函数
     50         sum[rt]--;
     51     else
     52         sum[rt]++;
     53     int m=mid;
     54     if(l==r) return ;
     55     if(val<=m) //val为集合的大小,小于m表示在左边
     56         update(flag,val,lson);
     57     else
     58         update(flag,val,rson);
     59 }
     60 
     61 void query(int k,int l,int r,int rt)
     62 {
     63     if(l==r)
     64     {
     65         printf("%d\n",l);
     66         return ;
     67     }
     68     int m=mid;
     69     if(k <= sum[rt<<1|1])
     70         query(k,rson);////右子树有大于等于k个数,第k个数肯定在右边
     71     else
     72         query(k-sum[rt<<1|1],lson);
     73 }
     74 
     75 int main()
     76 {
     77     int m;
     78     while(scanf("%d%d",&n,&m) != EOF)
     79     {
     80         init(n);
     81         build(1,n,1);
     82         while(m--)
     83         {
     84             int q,x,y;
     85             scanf("%d",&q);
     86             if(q==0)
     87             {
     88                 scanf("%d%d",&x,&y);
     89                 x=find(x);
     90                 y=find(y);
     91                 if(x==y)
     92                     continue;
     93                 update(false,rank[x],1,n,1);//先把x所在集合大小去掉
     94                 update(false,rank[y],1,n,1);
     95                 update(true,rank[x]+rank[y],1,n,1);//集合合并
     96                 fa[y]=x;
     97                 rank[x]+=rank[y];
     98             }
     99             else
    100             {
    101                 scanf("%d",&x);//第k小
    102                 query(x,1,n,1);
    103             }
    104         }
    105     }
    106     return 0;
    107 }

    一,线段树与树状数组动态更新k小元素:

    +线段树

    poj-2985

    可以与下面的树状数组相比较来理解,其实跟树状数组差不多。 

    View Code
      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 
      5 using namespace std;
      6 
      7 #define ls rt<<1
      8 #define rs rt<<1|1
      9 #define lson l,m,ls
     10 #define rson m+1,r,rs
     11 #define mid (l+r)>>1
     12 
     13 #define MAXN 200010
     14 
     15 int sum[MAXN<<2];//记录有几个点在节点的范围内
     16 int rank[MAXN],fa[MAXN];//rank表示集合的大小,fa表示根
     17 int n;
     18 
     19 void init(int n)
     20 {
     21     for(int i=0;i<=n;i++)
     22     {
     23         rank[i]=1;
     24         fa[i]=i;
     25     }
     26 }
     27 
     28 int find(int x)
     29 {
     30     if(x != fa[x])
     31         fa[x]=find(fa[x]);
     32     return fa[x];
     33 }
     34 
     35 void build(int l,int r,int rt)
     36 {
     37     if(l==1)//开始时每个集合的大小都为1故都在区间[1,r]内
     38         sum[rt]=n;
     39     else
     40         sum[rt]=0;
     41     if(l==r) return ;
     42     int m=mid;
     43     build(lson);
     44     build(rson);
     45 }
     46 
     47 void update(bool flag,int val,int l,int r,int rt)
     48 {
     49     if(!flag)//flag见main函数
     50         sum[rt]--;
     51     else
     52         sum[rt]++;
     53     int m=mid;
     54     if(l==r) return ;
     55     if(val<=m) //val为集合的大小,小于m表示在左边
     56         update(flag,val,lson);
     57     else
     58         update(flag,val,rson);
     59 }
     60 
     61 void query(int k,int l,int r,int rt)
     62 {
     63     if(l==r)
     64     {
     65         printf("%d\n",l);
     66         return ;
     67     }
     68     int m=mid;
     69     if(k <= sum[rt<<1|1])
     70         query(k,rson);////右子树有大于等于k个数,第k个数肯定在右边
     71     else
     72         query(k-sum[rt<<1|1],lson);
     73 }
     74 
     75 int main()
     76 {
     77     int m;
     78     while(scanf("%d%d",&n,&m) != EOF)
     79     {
     80         init(n);
     81         build(1,n,1);
     82         while(m--)
     83         {
     84             int q,x,y;
     85             scanf("%d",&q);
     86             if(q==0)
     87             {
     88                 scanf("%d%d",&x,&y);
     89                 x=find(x);
     90                 y=find(y);
     91                 if(x==y)
     92                     continue;
     93                 update(false,rank[x],1,n,1);//先把x所在集合大小去掉
     94                 update(false,rank[y],1,n,1);
     95                 update(true,rank[x]+rank[y],1,n,1);//集合合并
     96                 fa[y]=x;
     97                 rank[x]+=rank[y];
     98             }
     99             else
    100             {
    101                 scanf("%d",&x);//第k小
    102                 query(x,1,n,1);
    103             }
    104         }
    105     }
    106     return 0;
    107 }

     

    +树状数组

    看这里

    二,划分树与归并树求第k小元素:

    看大牛的博客上说的,划分树可以看成线段树+快排,归并树可以看成线段树+归并排序

    +划分树

    这里看看http://www.notonlysuccess.com/?s=2104

    poj 2104poj-2761都可以用划分树求。 

    题意就是求不同区间第k值:

    给出代码,还不是很理解:

    View Code
      1 #include <iostream>
      2 #include <cstdio>
      3 #include <algorithm>
      4 #include <cstring>
      5 
      6 using namespace std;
      7 
      8 #define ls rt<<1
      9 #define rs rt<<1|1
     10 #define lson l,m,ls
     11 #define rson m+1,r,rs
     12 
     13 #define MAXN 100001
     14 struct Seg_Tree
     15 {
     16     int l,r;
     17 }tt[MAXN<<2];
     18 int len;
     19 int sorted[MAXN];
     20 int toLeft[20][MAXN];
     21 int val[20][MAXN];
     22 
     23 void build(int d,int l,int r,int rt) 
     24 {
     25     tt[rt].l = l;
     26     tt[rt].r = r;
     27     if(tt[rt].l == tt[rt].r)    return ;
     28     int m = (l+r)>>1;
     29     int lsame = m - l + 1;
     30     for(int i = l ; i <= r ; i ++)
     31     {
     32         if(val[d][i] < sorted[m]) 
     33             lsame --;
     34     }
     35     int lpos = l;
     36     int rpos = m+1;
     37     int same = 0;
     38     for(int i = l ; i <= r ; i ++) 
     39     {
     40         if(i == l) 
     41             toLeft[d][i] = 0;
     42         else 
     43             toLeft[d][i] = toLeft[d][i-1];
     44         if(val[d][i] < sorted[m]) 
     45         {
     46             toLeft[d][i] ++;
     47             val[d+1][lpos++] = val[d][i];
     48         } 
     49         else if(val[d][i] > sorted[m]) 
     50             val[d+1][rpos++] = val[d][i];
     51         else 
     52         {
     53             if(same < lsame) 
     54             {
     55                 same ++;
     56                 toLeft[d][i] ++;
     57                 val[d+1][lpos++] = val[d][i];
     58             }
     59             else 
     60                 val[d+1][rpos++] = val[d][i];
     61         }
     62     }
     63     build(d+1,lson);
     64     build(d+1,rson);
     65 }
     66 
     67 int query(int k,int d,int l,int r,int rt) 
     68 {
     69     if(l == r) 
     70         return val[d][l];
     71     int s;
     72     int ss;
     73     if(l == tt[rt].l) 
     74     {
     75         s = toLeft[d][r];
     76         ss = 0;
     77     } 
     78     else 
     79     {
     80         s = toLeft[d][r] - toLeft[d][l-1];
     81         ss = toLeft[d][l-1];
     82     }
     83     if(s >= k)
     84     {
     85         int newl = tt[rt].l + ss;
     86         int newr = tt[rt].l + ss + s - 1; 
     87         return query(k,d+1,newl,newr,ls);
     88     } 
     89     else 
     90     {
     91         int m = (tt[rt].l + tt[rt].r)>>1;
     92         int bb = l - tt[rt].l - ss;
     93         int b = r - l + 1 - s;
     94         int newl = m + bb + 1;
     95         int newr = m + bb + b;
     96         return query(k-s,d+1,newl,newr,rs);
     97     }
     98 }
     99 
    100 int main() 
    101 {
    102     int n , m;
    103     while(scanf("%d%d",&n,&m) != EOF)
    104     {
    105         for(int i=1;i<=n;i++)
    106         {
    107             scanf("%d",&val[0][i]);
    108             sorted[i] = val[0][i];
    109         }
    110         sort(sorted + 1 , sorted + n + 1);
    111         build(0,1,n,1);
    112         while(m --) 
    113         {
    114             int l,r,k;
    115             scanf("%d%d%d",&l,&r,&k);
    116             printf("%d\n",query(k,0,l,r,1));
    117         }
    118     }
    119     return 0;
    120 }

     

    +归并树

    ++++未看

    小结:线段树与树状数组可以用来求区间固定,但是动态查询第K小元素的题,划分树与归并树可以求不同区间的第K小,具体看上面题。

  • 相关阅读:
    android 中文 api (43) —— Chronometer
    SVN客户端清除密码
    Android 中文 API (35) —— ImageSwitcher
    Android 中文API (46) —— SimpleAdapter
    Android 中文 API (28) —— CheckedTextView
    Android 中文 API (36) —— Toast
    Android 中文 API (29) —— CompoundButton
    android 中文 API (41) —— RatingBar.OnRatingBarChangeListener
    Android 中文 API (30) —— CompoundButton.OnCheckedChangeListener
    Android 中文 API (24) —— MultiAutoCompleteTextView.CommaTokenizer
  • 原文地址:https://www.cnblogs.com/Missa/p/2628921.html
Copyright © 2011-2022 走看看