zoj 2112 Dynamic Rankings 带修改区间第K大 动态主席树

Posted iat14

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了zoj 2112 Dynamic Rankings 带修改区间第K大 动态主席树相关的知识,希望对你有一定的参考价值。

pass

首先,个人觉得把这个数据结构理解成树状数组套主席树是十分不严谨的。主席树的本质是可持久化权值线段树与前缀和思想的结合。而动态主席树是可持久化权值线段树与树状数组思想的结合。并非树套树般的泾渭分明的叠加。

其次,大概讲下对动态主席树的理解。我们静态主席树中,第i个版本维护的是[1,i]的权值线段树,我们利用前缀和的思想,通过y的版本-x的版本得到[x,y]的权值线段树,从而剥离出一颗对应区间的权值线段树。我们考虑在这个情况下,如果需要修改第a[i]的值,那么从i,i+1,i+2......n的每个版本的线段树都要做出修改,显然代价难以承受。我们发现静态主席树继承了前缀和修改复杂度高,查询复杂度低的特点。我们想,能否利用其他数据结构的思想,与可持久化权值线段树结合呢?树状数组很好地满足了这个要求,修改和查询复杂度均为log级别,而且依旧有类似前缀和性质(这点我们从树状数组求区间和就能清晰地看出),只不过与某个位置相关的前缀,变成了log级别,这为我们修改每个前缀提供了可能。每当我们在i的x值+1时,我们就把i,i+lowbit(i)...的各个版本权值为x的下标都+1。当我们查询时,我们通过树状数组的思想,求出[1,x-1]和[1,y]的前缀和,再相减获得[x,y]的权值线段树即可。这道题需要离散化,注意权值线段树因为涉及到排名问题,原递增序列离散化后仍应该为递增序列。具体操作建议仔细阅读代码。

最后,这道题出题人卡了空间,动态主席树每次插入会比静态主席树的插入多消耗log级别的空间,而初始的数据规模又是操作的数据规模的5倍,因此用静态主席树操作最初的序列空间优势明显。所以标算是对最初的序列做了静态主席树,而对后来的修改做了动态主席树,这两颗主席树的下标权值是完全相同的。对于修改,我们只操作动态主席树,将原有的值对应权值下标-1,将新的值对应权值下标+1。对于询问,我们在两棵主席树上同步的进行,每次将动态主席树的左孩子大小之和与静态主席树的左孩子大小之和整体求和后,与排名k比较大小,从而决定两棵主席树是同步进入左子树还是右子树。

我会提供一份纯动态主席树,但因为空间问题无法AC的代码,学习动态主席树可以先看这个。然后提供一份静态动态主席树混合的AC代码。

动态主席树RE代码:

 

技术图片
  1 #include <cstdio>
  2 #include <map>
  3 #include <algorithm>
  4 using namespace std;
  5 const int MAXN = 61000,MAXM = 2500000;
  6 map <int,int> n2h;
  7 int sum,tot,n,q,T,tre;
  8 int cnt[MAXM],lson[MAXM],rson[MAXM]; 
  9 int h2n[MAXN],vec[MAXN],a[MAXN],l2v[MAXN],qry[MAXN][4];
 10 //cnt[x]:线段树节点x所代表区间的和
 11 //h2n[x]:将哈希值x转化为数值 n2h[x]:将数值x转化为哈希值
 12 //vec[x]:树状数组中,序列位置x的版本的根 tre 空白线段树的根 
 13 //a[x]:原序列x处元素 
 14 //l2v[x] 表示在当前权值下标范围内,序列位置x从根走到哪个节点了。
 15 //这是最难理解的一个数组。当没有权值下标限制时(或者说限制是[1,tot]时),l2v[x] = vec[x]。
 16 int lowbit(int x)
 17 {//lowbit
 18     return x & (-x);
 19 }
 20 int get_sum(int x)
 21 {//树状数组思想,求出当前权值下标范围,动态主席树中[1,x](序列位置)之和。 
 22     int res = 0;
 23     while (x > 0)
 24     {
 25         res += cnt[lson[l2v[x]]];
 26         x -= lowbit(x);
 27     }
 28     return res;
 29 }
 30 void build(int &x,int l,int r)
 31 {//权值线段树建树,传引用简化代码。 
 32     x = ++sum;
 33     cnt[x] = 0;
 34     if (l == r)
 35         return;
 36     int mid = l + r >> 1;
 37     build(lson[x],l,mid);
 38     build(rson[x],mid + 1,r);
 39 }
 40 void insert(int pre,int &x,int l,int r,int loc,int ad)
 41 {//插入新的版本,传引用简化代码。 
 42     x = ++sum;
 43     cnt[x] = cnt[pre] + ad;
 44     if (l == r)
 45         return;
 46     int mid = l + r >> 1;
 47     if (loc <= mid)
 48     {
 49         rson[x] = rson[pre];
 50         insert(lson[pre],lson[x],l,mid,loc,ad);
 51     }
 52     else
 53     {
 54         lson[x] = lson[pre];
 55         insert(rson[pre],rson[x],mid + 1,r,loc,ad);
 56     }
 57 }
 58 int query(int left,int right,int l,int r,int k)
 59 {//询问区间[left,right],权值下标限制范围为[l,r],排名为k的权值下标 
 60     if (l == r)
 61         return l; 
 62     int mid = l + r >> 1,tmp = get_sum(right) - get_sum(left);
 63     if (tmp >= k)
 64     {
 65         for (int i = left;i;i -= lowbit(i))
 66             l2v[i] = lson[l2v[i]];
 67         for (int i = right;i;i -= lowbit(i))
 68             l2v[i] = lson[l2v[i]];
 69         return query(left,right,l,mid,k);
 70     }
 71     for (int i = left;i;i -= lowbit(i))
 72         l2v[i] = rson[l2v[i]];
 73     for (int i = right;i;i -= lowbit(i))
 74         l2v[i] = rson[l2v[i]];
 75     return query(left,right,mid + 1,r,k - tmp);
 76 }
 77 void add(int x,int val,int ad)
 78 {//在序列位置x,权值val,增加ad 
 79     while (x <= n)
 80     {
 81         insert(vec[x],vec[x],1,tot,val,ad);
 82         x += lowbit(x);
 83     }
 84 }
 85 int main()
 86 {
 87     for (scanf("%d",&T);T;T--)
 88     {
 89         tot = 0;
 90         sum = 0;
 91         n2h.clear();
 92         scanf("%d%d",&n,&q);
 93         for (int i = 1;i <= n;i++)
 94         {
 95             scanf("%d",&a[i]);
 96             h2n[++tot] = a[i];
 97         }
 98         char s[10];
 99         for (int i = 1;i <= q;i++)
100         {
101             scanf("%s",s);
102             if (s[0] == Q)
103             {
104                 qry[i][0] = 0;
105                 scanf("%d%d%d",&qry[i][1],&qry[i][2],&qry[i][3]);
106             }else
107             {
108                 qry[i][0] = 1;
109                 scanf("%d%d",&qry[i][1],&qry[i][2]);
110                 h2n[++tot] = qry[i][2]; 
111             }
112         }
113         sort(h2n + 1,h2n + tot + 1);
114         tot = unique(h2n + 1,h2n + tot + 1) - (h2n + 1);
115         for (int i = 1;i <= tot;i++)
116             n2h[h2n[i]] = i;
117         build(tre,1,tot);
118         for (int i = 1;i <= n;i++)
119             vec[i] = tre; 
120         for (int i = 1;i <= n;i++)
121             add(i,n2h[a[i]],1);
122         for (int mi = 1;mi <= q;mi++)
123         {
124             if (qry[mi][0] == 0)
125             {
126                 for (int i = qry[mi][1] - 1;i;i -= lowbit(i))
127                     l2v[i] = vec[i];
128                 for (int i = qry[mi][2];i;i -= lowbit(i))
129                     l2v[i] = vec[i];
130                 printf("%d
",h2n[query(qry[mi][1] - 1,qry[mi][2],1,tot,qry[mi][3])]);
131             }
132             else
133             {
134                 add(qry[mi][1],n2h[a[qry[mi][1]]],-1);
135                 add(qry[mi][1],n2h[qry[mi][2]],1);
136                 a[qry[mi][1]] = qry[mi][2];
137             }
138         }
139     }
140     return 0;
141 }
View Code

静态动态主席树混合AC代码:

技术图片
  1 #include <cstdio>
  2 #include <map>
  3 #include <algorithm>
  4 using namespace std;
  5 const int MAXN = 61000,MAXM = 2500000;
  6 map <int,int> n2h;
  7 int sum,tot,n,q,T;
  8 int cnt[MAXM],lson[MAXM],rson[MAXM];
  9 int h2n[MAXN],tre[MAXN],vec[MAXN],a[MAXN],l2v[MAXN],qry[MAXN][4];
 10 int lowbit(int x)
 11 {
 12     return x & (-x);
 13 }
 14 int get_sum(int x)
 15 {
 16     int res = 0;
 17     while (x > 0)
 18     {
 19         res += cnt[lson[l2v[x]]];
 20         x -= lowbit(x);
 21     }
 22     return res;
 23 }
 24 void build(int &x,int l,int r)
 25 {
 26     x = ++sum;
 27     cnt[x] = 0;
 28     if (l == r)
 29         return;
 30     int mid = l + r >> 1;
 31     build(lson[x],l,mid);
 32     build(rson[x],mid + 1,r);
 33 }
 34 void insert(int pre,int &x,int l,int r,int loc,int ad)
 35 {
 36     x = ++sum;
 37     cnt[x] = cnt[pre] + ad;
 38     if (l == r)
 39         return;
 40     int mid = l + r >> 1;
 41     if (loc <= mid)
 42     {
 43         rson[x] = rson[pre];
 44         insert(lson[pre],lson[x],l,mid,loc,ad);
 45     }
 46     else
 47     {
 48         lson[x] = lson[pre];
 49         insert(rson[pre],rson[x],mid + 1,r,loc,ad);
 50     }
 51 }
 52 int query(int lx,int rx,int left,int right,int l,int r,int k)
 53 {
 54     if (l == r)
 55         return l; 
 56     int mid = l + r >> 1,tmp = get_sum(right) - get_sum(left) + cnt[lson[rx]] - cnt[lson[lx]];
 57     if (tmp >= k)
 58     {
 59         for (int i = left;i;i -= lowbit(i))
 60             l2v[i] = lson[l2v[i]];
 61         for (int i = right;i;i -= lowbit(i))
 62             l2v[i] = lson[l2v[i]];
 63         return query(lson[lx],lson[rx],left,right,l,mid,k);
 64     }
 65     for (int i = left;i;i -= lowbit(i))
 66         l2v[i] = rson[l2v[i]];
 67     for (int i = right;i;i -= lowbit(i))
 68         l2v[i] = rson[l2v[i]];
 69     return query(rson[lx],rson[rx],left,right,mid + 1,r,k - tmp);
 70 }
 71 void add(int x,int val,int ad)
 72 {
 73     while (x <= n)
 74     {
 75         insert(vec[x],vec[x],1,tot,val,ad);
 76         x += lowbit(x);
 77     }
 78 }
 79 int main()
 80 {
 81     for (scanf("%d",&T);T;T--)
 82     {
 83         tot = 0;
 84         sum = 0;
 85         n2h.clear();
 86         scanf("%d%d",&n,&q);
 87         for (int i = 1;i <= n;i++)
 88         {
 89             scanf("%d",&a[i]);
 90             h2n[++tot] = a[i];
 91         }
 92         char s[10];
 93         for (int i = 1;i <= q;i++)
 94         {
 95             scanf("%s",s);
 96             if (s[0] == Q)
 97             {
 98                 qry[i][0] = 0;
 99                 scanf("%d%d%d",&qry[i][1],&qry[i][2],&qry[i][3]);
100             }else
101             {
102                 qry[i][0] = 1;
103                 scanf("%d%d",&qry[i][1],&qry[i][2]);
104                 h2n[++tot] = qry[i][2]; 
105             }
106         }
107         sort(h2n + 1,h2n + tot + 1);
108         tot = unique(h2n + 1,h2n + tot + 1) - (h2n + 1);
109         for (int i = 1;i <= tot;i++)
110             n2h[h2n[i]] = i;
111         build(tre[0],1,tot);
112         for (int i = 1;i <= n;i++)
113             insert(tre[i - 1],tre[i],1,tot,n2h[a[i]],1);
114         for (int i = 1;i <= n;i++)
115             vec[i] = tre[0]; 
116         for (int mi = 1;mi <= q;mi++)
117         {
118             if (qry[mi][0] == 0)
119             {
120                 for (int i = qry[mi][1] - 1;i;i -= lowbit(i))
121                     l2v[i] = vec[i];
122                 for (int i = qry[mi][2];i;i -= lowbit(i))
123                     l2v[i] = vec[i];
124                 printf("%d
",h2n[query(tre[qry[mi][1] - 1],tre[qry[mi][2]],qry[mi][1] - 1,qry[mi][2],1,tot,qry[mi][3])]);
125             }
126             else
127             {
128                 add(qry[mi][1],n2h[a[qry[mi][1]]],-1);
129                 add(qry[mi][1],n2h[qry[mi][2]],1);
130                 a[qry[mi][1]] = qry[mi][2];
131             }
132         }
133     }
134     return 0;
135 }
View Code

 

以上是关于zoj 2112 Dynamic Rankings 带修改区间第K大 动态主席树的主要内容,如果未能解决你的问题,请参考以下文章

zoj 2112 Dynamic Rankings

ZOJ 2112 Dynamic Rankings

ZOJ - 2112 Dynamic Rankings

●ZOJ 2112 Dynamic Rankings

zoj2112 Dynamic Rankings 动态区间第k大,树状数组套平衡树

ZOJ 2112 Dynamic Rankings(带修改的区间第K大,分块+二分搜索+二分答案)