Treap——题目方法总结

来源:互联网 发布:无网络的手机txt阅读器 编辑:程序博客网 时间:2024/05/29 04:51

一、查询整体区间第K大 && 序列中比 x 小的数的个数

例题:spoj3273.ORDERSET——初始一个空序列,支持插入、删除一个数,查询整个序列中的第K大和整个序列中小于x的数的个数。

难度:**

这是Treap的模版题,操作也都是基本操作,不错的一道模版题,但是spoj实在太慢了...写不好会莫名TLE

#include <cstdio>  #include <cstring>  #include <algorithm>  #define inf 1500000000    using namespace std;    typedef long long LL;  const int N = 300005;    struct treap {      int ch[2], val, sz; unsigned int wt;      void Set(int vl) { val = vl, wt = rand() * rand() * rand(), sz = 1; }  } t[N];  int rt, n, tz, q;    void update(int x) {       t[x].sz = t[t[x].ch[0]].sz + t[t[x].ch[1]].sz + 1;   }  void rot(int &x, bool ty) {       int y = t[x].ch[ty]; t[x].ch[ty] = t[y].ch[!ty], t[y].ch[!ty] = x;      update(x), update(y), x = y;   }  void add(int &x, int val) {      if (!x) { t[x = ++ tz].Set(val); return ; }      if (t[x].val == val) return ;      bool ty = val > t[x].val;      add (t[x].ch[ty], val);      (t[t[x].ch[ty]].wt > t[x].wt) ? rot(x, ty) : update(x);  }  void del(int &x, int val) {      if (!x) return ;      if (t[x].val == val) {          bool ty = t[t[x].ch[1]].wt > t[t[x].ch[0]].wt;          if (!t[x].ch[ty]) { x = 0; return ; }          rot(x, ty), del(t[x].ch[!ty], val);      } else del(t[x].ch[val > t[x].val], val);      update(x);  }  int kth(int k) {      int x = rt;      if (t[x].sz < k) return inf;      for (; k != t[t[x].ch[0]].sz + 1;) (k <= t[t[x].ch[0]].sz) ? x = t[x].ch[0] : (k -= t[t[x].ch[0]].sz + 1, x = t[x].ch[1]);      return t[x].val;  }  int Count(int x) {      if (!x) return 0;      if (t[x].val < q) return Count(t[x].ch[1]) + t[t[x].ch[0]].sz + 1;      else return Count(t[x].ch[0]);  }  void init() {      scanf("%d", &n);  }  void doit() {      for (int i = 1; i <= n; i ++) {          int x; char ty;          scanf (" %c %d", &ty, &x);          if (ty == 'I') add(rt, x);          else if (ty == 'D') del(rt, x);          else if (ty == 'K') {              x = kth(x);              (x != inf) ? printf ("%d\n", x) : puts("invalid");          }          else q = x, printf ("%d\n", Count(rt));      }  }  int main()  {      init();      doit();      return 0;  }  

二、查询一个序列中第一大于(等于)x和小于(等于)x的数

例题:poj2892——有一个1n的序列,支持破坏一个数回复一个数,查询数x所在的没有被破坏的最长区间

难度:***

这道题用Treap维护的不是整个序列,而是被破环的数组成的序列,这个是第一次见到,应该算一种方法。这样查询的时候就可以在Treap中查找第一个大于、小于的数了。

/*Author: JDDPROG: poj2892.Tunnel WarfareDATE: 2016.5.16*/#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int MAX_N = 100005;int n, Q, tsz, rt, l, r;struct Treap {int ch[2], vl;unsigned int wt;void set(int _vl) {vl = _vl; wt = rand() * rand() * rand();}}t[MAX_N];void tree_rot(int &x, bool ty){int y = t[x].ch[ty]; t[x].ch[ty] = t[y].ch[!ty]; t[y].ch[!ty] = x;x = y;}void tree_add(int &x, int val){if (!x) { t[x = ++ tsz].set(val); return; }if (t[x].vl == val) return;bool ty = val > t[x].vl;tree_add(t[x].ch[ty], val);if (t[t[x].ch[ty]].wt > t[x].wt) tree_rot(x, ty);}void tree_del(int &x, int val){if (!x) return;if (t[x].vl == val) {bool ty = t[t[x].ch[1]].wt > t[t[x].ch[0]].wt;if (!t[x].ch[ty]) { x = 0; return; }tree_rot(x, ty); tree_del(t[x].ch[!ty], val);} else tree_del(t[x].ch[val > t[x].vl], val);}void tree_find(int x, int val){if (!x) return;if (t[x].vl >= val && r >= t[x].vl) r = t[x].vl;if (t[x].vl <= val && l <= t[x].vl) l = t[x].vl;if (val > t[x].vl) tree_find(t[x].ch[1], val);else if (val < t[x].vl)  tree_find(t[x].ch[0], val);}void init(){scanf("%d%d", &n, &Q);}int st[MAX_N], top = 0;void doit(){char ty; int x;while (Q --) {scanf(" %c ", &ty);if (ty == 'D') {scanf("%d", &x);tree_add(rt, x); st[++ top] = x;} else if (ty == 'R') {tree_del(rt, st[top]); top --;} else if (ty == 'Q') {scanf("%d", &x);l = 0, r = n + 1;tree_find(rt, x);if (l == x && r == x) printf("0\n");else printf("%d\n", r - l - 1);}}}int main(){init();doit();return 0;}




0 0
原创粉丝点击