[关闭]
@01010101 2018-11-05T20:43:28.000000Z 字数 2463 阅读 1069

可持久化数据结构

可持久化


我居然在这个时候还在学新算法。
好吧,这一切都是为了noip2017DAY1T3列队。表示自己没怎么看懂动态开点线段树。然后就怒学一波主席树。发现也不难啊~为什么才学的时候觉得那么遥不可及。

每次插入,就是建一棵新的树也就是log(n)的空间复杂度。总空间复杂度O(nlogn^2).发现当题目强制在线的时候,主席树才有用处。否则,就直接将询问排序(常数翻倍)。

这题是主席树求区间第k大。

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <algorithm>
  5. using namespace std;
  6. const int maxn = 100000 + 10;
  7. int n,m,a[maxn],rt[maxn],p,x,y,z;
  8. int cnt,s[maxn];
  9. struct node{
  10. int lc,rc,val;
  11. }t[maxn << 6];
  12. void inserts(int &u,int l,int r,int a){
  13. if(!u) u = ++cnt;
  14. t[u].val++;
  15. if(l == r) return;
  16. int mid = (l + r) >> 1;
  17. if(a <= mid) inserts(t[u].lc,l,mid,a);
  18. else inserts(t[u].rc,mid + 1,r,a);
  19. }
  20. void merge(int &u1,int u2){
  21. if(!u1) {u1 = u2;return;}
  22. if(!u2) return;
  23. t[u1].val += t[u2].val;
  24. merge(t[u1].lc,t[u2].lc);
  25. merge(t[u1].rc,t[u2].rc);
  26. }
  27. int query(int u1,int u2,int l,int r,int k){
  28. if(l == r) return s[l];
  29. int mid = (l + r) >> 1;
  30. int tmp = t[t[u1].lc].val - t[t[u2].lc].val;
  31. if(k <= tmp) return query(t[u1].lc,t[u2].lc,l,mid,k);
  32. return query(t[u1].rc,t[u2].rc,mid + 1,r,k - tmp);
  33. }
  34. int main(){
  35. // freopen("a.txt","r",stdin);
  36. scanf("%d%d",&n,&m);
  37. for(int i = 1; i <= n; ++i){scanf("%d",&a[i]);s[i] = a[i];}
  38. sort(s + 1,s + n + 1);
  39. p = unique(s + 1,s + n + 1) - s - 1;
  40. for(int i = 1; i <= p; ++i) {
  41. inserts(rt[i],1,n,lower_bound(s + 1,s + p + 1,a[i]) - s);
  42. merge(rt[i],rt[i - 1]);
  43. }
  44. while(m--){
  45. scanf("%d%d%d",&x,&y,&z);
  46. printf("%d\n",query(rt[y],rt[x - 1],1,n,z));
  47. }
  48. return 0;
  49. }

51NOD 1295 XOR key
给出一个长度为N的正整数数组A,再给出Q个查询,每个查询包括3个数,L, R, X (L <= R)。求A[L] 至 A[R] 这R - L + 1个数中,与X 进行异或运算(Xor),得到的最大值是多少?

可持久化trie树。
这里把所有rt向后移了一位。因为原题中的L可能为0.

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstring>
  4. #include <algorithm>
  5. #include <queue>
  6. #include <vector>
  7. using namespace std;
  8. int read(){
  9. char ch;int op=1;
  10. while((ch=getchar())<'0'||ch>'9') if(ch=='-') op=-1;
  11. int ret=ch-'0';
  12. while((ch=getchar())>='0'&&ch<='9') ret=ret*10+ch-'0';
  13. return ret*op;
  14. }
  15. void write(int x){
  16. if(x<0) putchar('-'),x=-x;
  17. if(x>=10) write(x/10);
  18. putchar('0'+x%10);
  19. }
  20. const int N=50005,M=3000000;
  21. int n,Q,idx=1,rt[N]={1},son[M][2],sz[M];
  22. void insert(int i,int x){
  23. int now=rt[i]=++idx;
  24. int old=rt[i-1];
  25. for(int i=31;i>=0;--i){
  26. sz[now]=sz[old]+1;
  27. int cur=(x>>i)&1;
  28. son[now][cur^1]=son[old][cur^1];
  29. son[now][cur]=++idx;
  30. now=son[now][cur];
  31. old=son[old][cur];
  32. }
  33. sz[now]=sz[old]+1;
  34. }
  35. int query(int l,int r,int x){
  36. int old=rt[l],now=rt[r],ans=0;
  37. for(int i=31;i>=0;--i){
  38. int cur=(x>>i)&1;
  39. int delta_sze=sz[son[now][!cur]]-sz[son[old][!cur]];
  40. if(delta_sze) now=son[now][!cur],old=son[old][!cur],ans=ans<<1|1;
  41. else now=son[now][cur],old=son[old][cur],ans=ans<<1;
  42. }
  43. return ans;
  44. }
  45. int main(){
  46. // freopen("a.txt","r",stdin);
  47. n=read();Q=read();
  48. for(int i=1;i<=n;++i) {
  49. insert(i,read());
  50. }
  51. int l,r,x;
  52. while(Q--){
  53. x=read();l=read();r=read();
  54. write(query(l,r+1,x));
  55. putchar('\n');
  56. }
  57. return 0;
  58. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注