zoukankan      html  css  js  c++  java
  • 可持久化数据结构题目泛做。

    个人理解:

    每个新的线段树的一个结点保存的是1...位置 i中的数字在相应的区间上有几个。

    然后我们用r-(l-1)得到的就是l...r上的中字在相应的区间中出现了几个。

    题目1 POJ2104

    题目大意:静态查询区间第K小值。

    裸的可持久化线段树。

     1 #include <cstdlib>
     2 #include <iostream>
     3 #include <algorithm>
     4 #include <cstdio>
     5 #include <cstring>
     6 
     7 using namespace std;
     8 const int N = 100000 + 5;
     9 
    10 struct SegTree {
    11   int l, r, size;
    12 }Node[N * 30];
    13 
    14 struct data {
    15   int v, pos;
    16   bool operator < (const data &k) const {
    17     return v < k.v;
    18   }
    19 }a[N];
    20 
    21 int n, m, rank[N], l, r, k, root[N], tot;
    22 
    23 void build(int &o, int l, int r) {
    24   o = ++ tot;
    25   Node[o].l = Node[o].r = Node[o].size = 0;
    26   if(l >= r) return;
    27   int mid = (l + r) >> 1;
    28   build(Node[o].l, l, mid);
    29   build(Node[o].r, mid + 1, r);
    30 }
    31 
    32 void update(int pre, int &o, int l, int r, int kth) {
    33   o = ++ tot;
    34   Node[o] = Node[pre];
    35   Node[o].size ++;
    36   if(l >= r) return;
    37   int mid = (l + r) >> 1;
    38   if(kth <= mid)
    39     update(Node[pre].l, Node[o].l, l, mid, kth);
    40   else
    41     update(Node[pre].r, Node[o].r, mid + 1, r, kth);
    42 }
    43 
    44 int query(int r1, int r2, int l, int r, int kth) {
    45   if(l >= r) return l;
    46   int lc = Node[Node[r2].l].size - Node[Node[r1].l].size;
    47   int mid = (l + r) >> 1;
    48   if(lc >= kth)
    49     return query(Node[r1].l, Node[r2].l, l, mid, kth);
    50   else
    51     return query(Node[r1].r, Node[r2].r, mid + 1, r, kth - lc);
    52 }
    53 
    54 int main() {
    55   scanf("%d%d", &n, &m);
    56   for(int i = 1; i <= n; ++ i) {
    57     scanf("%d", &a[i].v);
    58     a[i].pos = i;
    59   }
    60   sort(a + 1, a + n + 1);
    61   for(int i = 1; i <= n; ++ i)
    62     rank[a[i].pos] = i;
    63   build(root[0], 1, n);
    64   for(int i = 1; i <= n; ++ i)
    65     update(root[i - 1], root[i], 1, n, rank[i]);
    66   for(int i = 1; i <= m; ++ i) {
    67     scanf("%d%d%d", &l, &r, &k);
    68     printf("%d
    ", a[query(root[l - 1], root[r], 1, n, k)].v);
    69   }
    70   return 0;
    71 }
    2104

    题目2 SPOJ Count On a Tree 1

    题目大意:

    给一个树,求路径(u,v)上的第k小值。

    算法讨论: 可持久化线段树。

    我们考虑序列的做法是一个元素在前一个元素上建立新的线段树。那么对于一个树来说,就是在父亲的基础上建立一棵新的线段树。

    所有我们有如下的做法:先搞出每个点的权值的rank,然后对树DFS,求出DFS序,则每个点就以各自的DFS序为一个新根,建立在FA的DFS序上。

    在查询的时候,用U和V的线段树权值减去LCA和FA(LCA)的线段树权值即可。

    坑点:一定要注意去重。然后再搞RANK。

    代码:

      1 #include <cstdlib>
      2 #include <iostream>
      3 #include <cstring>
      4 #include <algorithm>
      5 #include <cstdio>
      6 
      7 using namespace std;
      8 const int N = 100000 + 5;
      9 inline int read() {
     10   int x = 0;
     11   char c = getchar();
     12   while(!isdigit(c)) c = getchar();
     13   while(isdigit(c)) {
     14     x = x * 10 + c - '0';
     15     c = getchar();
     16   }
     17   return x;
     18 }
     19 
     20 int n, m, tail, tot, cnt, tim;
     21 int v[N], seq[N], num[N], seg[N], fa[N];
     22 int f[N][20], head[N], depth[N], rank[N], root[N];
     23 
     24 struct Edge {
     25   int from, to, next;
     26 }edges[N << 1];
     27 
     28 struct SegTree {
     29   int l, r, size;
     30 }Node[N * 40];
     31 
     32 void insert(int from, int to) {
     33   ++ cnt;
     34   edges[cnt].from = from; edges[cnt].to = to;
     35   edges[cnt].next = head[from]; head[from] = cnt;
     36 }
     37 
     38 void dfs(int u, int ff) {
     39   fa[u] = ff;
     40   ++ tim; num[u] = tim; seg[tim] = u;
     41   for(int i = head[u]; i; i = edges[i].next) {
     42     int v = edges[i].to;
     43     if(v != ff) {
     44       depth[v] = depth[u] + 1;
     45       dfs(v, u);
     46     }
     47   }
     48 }
     49 
     50 void prepare() {
     51   memset(f, -1, sizeof f);
     52   for(int i = 1; i <= n; ++ i) f[i][0] = fa[i];
     53   for(int j = 1; (1 << j) <= n; ++ j) {
     54     for(int i = 1; i <= n; ++ i) {
     55       if(f[i][j - 1] != -1) {
     56         f[i][j] = f[f[i][j - 1]][j - 1];
     57       }
     58     }
     59   }
     60 }
     61 
     62 int lca(int a, int b) {
     63   int i;
     64   if(depth[a] < depth[b]) swap(a, b);
     65   for(i = 0; (1 << i) <= depth[a]; ++ i);
     66   -- i;
     67   for(int j = i; j >= 0; -- j)
     68     if(depth[a] - depth[b] >= (1 << j))
     69       a = f[a][j];
     70   if(a == b) return a;
     71   for(int j = i; j >= 0; -- j) {
     72     if(f[a][j] != -1 && f[a][j] != f[b][j]) {
     73       a = f[a][j]; b = f[b][j];
     74     }
     75   }
     76   return f[a][0];
     77 }
     78 
     79 void build(int &o, int l, int r) {
     80   o = ++ tot;
     81   Node[o].l = Node[o].r = Node[o].size = 0;
     82   if(l >= r) return;
     83   int mid = (l + r) >> 1;
     84   build(Node[o].l, l, mid);
     85   build(Node[o].r, mid + 1, r);
     86 }
     87 
     88 void update(int pre, int &o, int l, int r, int kth) {
     89   o = ++ tot;
     90   Node[o] = Node[pre];
     91   Node[o].size ++;
     92   if(l >= r) return;
     93   int mid = (l + r) >> 1;
     94   if(kth <= mid)
     95     update(Node[pre].l, Node[o].l, l, mid, kth);
     96   else
     97     update(Node[pre].r, Node[o].r, mid + 1, r, kth);
     98 }
     99 
    100 int query(int r1, int r2, int r3, int r4, int l, int r, int kth) {
    101   if(l >= r) return l;
    102   int lc = Node[Node[r1].l].size + Node[Node[r2].l].size - Node[Node[r3].l].size - Node[Node[r4].l].size;
    103   int mid = (l + r) >> 1;
    104   if(lc >= kth)
    105     return query(Node[r1].l, Node[r2].l, Node[r3].l, Node[r4].l, l, mid, kth);
    106   else return query(Node[r1].r, Node[r2].r, Node[r3].r, Node[r4].r, mid + 1, r, kth - lc);
    107 }
    108 
    109 int Q(int x, int y, int z) {
    110   int Lca = lca(x, y);
    111   return seq[query(root[num[x]], root[num[y]], root[num[Lca]], root[num[fa[Lca]]], 1, tail, z)];
    112 }
    113 
    114 int main() {
    115   //int __size__ = 64 << 20; // 64MB
    116   //char *__p__ = (char*)malloc(__size__) + __size__;
    117   //__asm__("movl %0, %%esp
    " :: "r"(__p__));
    118   int x, y, z;
    119   n = read(); m = read();
    120   for(int i = 1; i <= n; ++ i) {
    121     v[i] = read();
    122     seq[i] = v[i];
    123   }
    124   sort(seq + 1, seq + n + 1);
    125   tail = unique(seq + 1, seq + n + 1) - seq - 1;
    126   for(int i = 1; i <= n; ++ i)
    127     rank[i] = lower_bound(seq + 1, seq + tail + 1, v[i]) - seq;
    128   for(int i = 1; i < n; ++ i) {
    129     x = read(); y = read();
    130     insert(x, y); insert(y, x);
    131   }
    132   depth[1] = 1; num[0] = 0; seg[0] = 0;
    133   dfs(1, 0); prepare();
    134   build(root[0], 1, tail);
    135   for(int i = 1; i <= n; ++ i) {
    136     int t = seg[i];
    137     update(root[num[fa[t]]], root[i], 1, tail, rank[t]);
    138   }
    139   bool flag = false;
    140   for(int i = 1; i <= m; ++ i) {
    141     x = read(); y = read(); z = read();
    142     //x ^= lastans;
    143     if(flag)
    144       printf("
    %d", Q(x, y, z));
    145     else {
    146       printf("%d", Q(x, y, z));
    147       flag = true;
    148     }
    149   }
    150   return 0;
    151 }
    COT

    题目3 SPOJ Count On a Tree II (还没写呢)

    题目大意:

    给一个树,每个点都有一个权值。求(u,v)路径上有多少本质不同的权值。

    n <= 4W, m <= 10W

    算法讨论:

    首先感觉这个题可以树上莫队搞掉。哪天开心了写一发,今天先贴可持久化的做法。

    题目4 HDU4417 SuperMario

    题目大意:

    给定一个数列,求区间L_R内小于等于H的数有多少。

    算法讨论:

    分块?别想了你,32M内存,卡掉你不在话下。而且多组数据,O(Nsqrt(N)*T)估计险过吧。还是来YY正解。

    可持久化线段树。首先把序列离散化建立可持久化线段树。

    然后对于每个要查询的数,先查询出其在原序列中的Rank,由于是小于等于它的数有多少,所以 upper_bound。

    否则就Lower_boud。接着我们在权值线段树上走。如果这个数比当前区间的mid大,就加上左子树的size差然后去右边查询。

    否则就去左边查询。自己还傻傻的每次都去叶子结点查询。

    自己要注意的几个地方:

    首先自己离散化之后的数组大小和权值线段树的右边界老不改,如果还用N,就是这题14遍的TLE。

    还就是如果当前要查询的数是整个序列中最小的,那么返回值是-1,则要记得判断为0.

    鸣谢SMZ大神指导。

      1 #include <cstdlib>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 #include <iostream>
      6 
      7 using namespace std;
      8 
      9 const int N = 100000 + 5;
     10 inline int read() {
     11   int x = 0;
     12   char c = getchar();
     13   while(!isdigit(c)) c = getchar();
     14   while(isdigit(c)) {
     15     x = x * 10 + c - '0';
     16     c = getchar();
     17   }
     18   return x;
     19 }
     20 
     21 struct data {
     22   int v, pos;
     23   bool operator < (const data &k) const {
     24     return v < k.v;
     25   }
     26 }a[N];
     27 
     28 struct SegTree {
     29   int size, l, r;
     30 }Node[N * 19];
     31 
     32 int n, m, tot, ans, tail;
     33 int rk[N], root[N], v[N], seq[N];
     34 
     35 void build(int &o, int l, int r) {
     36   o = ++ tot;
     37   Node[o].l = Node[o].r = Node[o].size = 0;
     38   if(l >= r) return;
     39   int mid = (l + r) >> 1;
     40   build(Node[o].l, l, mid);
     41   build(Node[o].r, mid + 1, r);
     42 }
     43 
     44 void update(int pre, int &o, int l, int r, int kth) {
     45   o = ++ tot;
     46   Node[o] = Node[pre];
     47   Node[o].size ++;
     48   if(l >= r) return;
     49   int mid = (l + r) >> 1;
     50   if(kth <= mid)
     51     update(Node[pre].l, Node[o].l, l, mid, kth);
     52   else
     53     update(Node[pre].r, Node[o].r, mid + 1, r, kth);
     54 }
     55 
     56 int query(int r1, int r2, int l, int r, int kth) {
     57   if(l > r) return 0;
     58   if(l == r)
     59     return Node[r2].size - Node[r1].size;
     60   int mid = (l + r) >> 1;
     61   if(kth > mid) {
     62     return (Node[Node[r2].l].size - Node[Node[r1].l].size) + query(Node[r1].r, Node[r2].r, mid + 1, r, kth);
     63   }
     64   else {
     65     return query(Node[r1].l, Node[r2].l, l, mid, kth);
     66   }
     67 }
     68 
     69 void Q(int x, int y, int z, int kth) {
     70   ans = query(root[x - 1], root[y], 1, tail, kth);
     71 }
     72 
     73 int main() {
     74   int t, x, y, z, tt = 0, zk;
     75   t = read();
     76   while(t --) {
     77     for(int i = 1; i <= tot; ++ i)
     78       Node[i].size = Node[i].l = Node[i].r = 0;
     79     tot = 0;
     80     ++ tt;
     81     printf("Case %d:
    ", tt);
     82     n = read(); m = read();
     83     for(int i = 1; i <= n; ++ i) {
     84       v[i] = read();
     85       seq[i] = v[i];
     86     }
     87     sort(seq + 1, seq + n + 1);
     88     tail = unique(seq + 1, seq + n + 1) - seq - 1;
     89     for(int i = 1; i <= n; ++ i)
     90       rk[i] = lower_bound(seq + 1, seq + tail + 1, v[i]) - seq;
     91     build(root[0], 1, tail);
     92     for(int i = 1; i <= n; ++ i)
     93       update(root[i - 1], root[i], 1, tail, rk[i]);
     94     for(int i = 1; i <= m; ++ i) {
     95       x = read(); y = read(); z = read();
     96       x ++; y ++;
     97       zk = upper_bound(seq + 1, seq + tail + 1, z) - seq - 1;
     98       if(zk > 0)
     99         Q(x, y, z, zk);
    100       else ans = 0;
    101       printf("%d
    ", ans);
    102     }
    103   }
    104   return 0;
    105 }
    4417

    题目5 51nod 1175 区间第K大。

    裸题啊。

    #include <cstdlib>
    #include <cstring>
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    const int N = 50000 + 5;
    
    int n, tail, cnt, m;
    int a[N], que[N], rank[N], root[N];
    
    struct SegMent {
    	int l, r, size;
    }Node[N * 20];
    
    void build(int &o, int l, int r) {
    	o = ++ cnt;
    	Node[o].l = Node[o].r = Node[o].size = 0;
    	if(l >= r) return;
    	int mid = (l + r) >> 1;
    	build(Node[o].l, l, mid);
    	build(Node[o].r, mid + 1, r);
    }
    
    void update(int o, int &p, int l, int r, int kth) {
    	p = ++ cnt;
    	Node[p] = Node[o];
    	Node[p].size ++;
    	if(l >= r) return;
    	int mid = (l + r) >> 1;
    	if(kth <= mid)
    	  update(Node[o].l, Node[p].l, l, mid, kth);
    	else
    	  update(Node[o].r, Node[p].r, mid + 1, r, kth);
    }
    
    int query(int r1, int r2, int l, int r, int kth) {
    	if(l >= r) return l;
    	int lc = Node[Node[r2].l].size - Node[Node[r1].l].size;
    	int mid = (l + r) >> 1;
    	if(lc >= kth)
    	  return query(Node[r1].l, Node[r2].l, l, mid, kth);
    	else
    	  return query(Node[r1].r, Node[r2].r, mid + 1, r, kth - lc);
    }
    
    int main() {
    	scanf("%d", &n);
    	for(int i = 1; i <= n; ++ i) {
    		scanf("%d", &a[i]);
    		que[++ tail] = a[i];
    	}
    	sort(que + 1, que + tail + 1);
    	tail = unique(que + 1, que + tail + 1) - que - 1;
    	for(int i = 1; i <= n; ++ i) rank[i] = lower_bound(que + 1, que + tail + 1, a[i]) - que;
    	build(root[0], 1, tail);
    	for(int i = 1; i <= n; ++ i)
    	  update(root[i - 1], root[i], 1, tail, rank[i]);
    	scanf("%d", &m);
    	for(int i = 1; i <= m; ++ i) {
    		int l, r, k;
    		scanf("%d%d%d", &l, &r, &k);
    		l ++; r ++;
    		printf("%d
    ", que[query(root[l - 1], root[r], 1, tail, (r - l + 1) - k + 1)]);
    	}
    	system("pause");
    	return 0;
    }
    
  • 相关阅读:
    Html、Vue——本地文件上传弹框+读取本地文件内容
    git-基本操作
    Selenium(二)---无界面模式+滑动底部
    Selenium(一)---Selenium的安装和使用
    Nginx+win10安装配置
    Tinghua Data Mining 9
    Tinghua Data Mining 8
    Tinghua Data Mining 7
    Tinghua Data Mining 6
    Tinghua Data Mining 5
  • 原文地址:https://www.cnblogs.com/sxprovence/p/5349774.html
Copyright © 2011-2022 走看看