zoukankan      html  css  js  c++  java
  • 主席树 刷题记录

    一些调试经验

    • 要修改某个时间点的树时一定要再整一个新的树出来,不能在上一个树的根节点就这样修改,因为某一个时间点的树永远连着以前的,改了的话会对前面的版本产生影响
    • cnt一直在累加,用cnt赋值的时候注意再注意。

    洛谷P3834 【模板】可持久化线段树 1(主席树)

    • 静态区间第 k
    • 先把输入的a[i]离散化,假设最后有k个数,再从1~k建树
    • 然后从1~n遍历,v[i]表示数i的个数,每个i新建一颗线段树
    • 对于询问(l,r),用root[r]的树减去root[l-1]的树即可得到给(l,r)建的线段树
    • 在(l,r)建的线段树里查询第k小即可。
    • 代码:
       1 #include <bits/stdc++.h>
       2 #define nmax 200010
       3 
       4 using namespace std;
       5 int a[nmax], c[nmax], ls[nmax*40], rs[nmax*40], v[nmax*40], root[nmax];
       6 struct px{
       7     int x, id;
       8     bool operator < (const px& tmp) const{
       9         return tmp.x > x;
      10     }
      11 }b[nmax];
      12 int cnt=0;
      13 
      14 int build(int l, int r){
      15     cnt++;
      16     int u = cnt;
      17     if(l==r) return u;
      18     int mid = (l+r)>>1 ;
      19     ls[u] = build(l, mid);
      20     rs[u] = build(mid+1, r);
      21     return u;
      22 }
      23 
      24 void upd(int u, int k, int l, int r, int u2){
      25     v[u2] = v[u]+1;
      26     if(l==r) return;
      27     int mid = (l+r)>>1 ;
      28     if(k<=mid) {
      29         rs[u2] = rs[u];
      30         ls[u2] = ++cnt;
      31         upd(ls[u], k, l, mid, ls[u2]);
      32     }else{
      33         ls[u2] = ls[u];
      34         rs[u2] = ++cnt;
      35         upd(rs[u], k, mid+1, r, rs[u2]);
      36     }
      37 }
      38 int myfind(int u, int u2, int k, int l, int r){
      39     if(l==r) return l;
      40     int num = v[ ls[u2] ] - v[ ls[u] ];
      41     int mid = (l+r)>>1;
      42     if(k<=num) return myfind(ls[u], ls[u2], k, l, mid);
      43     else return myfind(rs[u], rs[u2], k-num, mid+1, r);
      44 }
      45 
      46 int main(){
      47     int n, m;
      48     scanf("%d%d", &n, &m);
      49     for (int i=1; i<=n; i++) {
      50         scanf("%d", &b[i].x);
      51         b[i].id = i;
      52     } 
      53     sort(b+1, b+n+1);
      54     int idx=1;
      55     c[ b[1].id ] = 1;
      56     a[1] = b[1].x;
      57     for (int i=2; i<=n; i++) {
      58         if(b[i].x!=b[i-1].x) idx++;
      59         c[ b[i].id ] = idx;
      60         a[ idx ] = b[i].x;
      61     }
      62     build(1, idx);
      63     root[0] = 1;
      64     for (int i=1; i<=n; i++) {
      65         root[i] = ++cnt;
      66         upd(root[i-1], c[i], 1, idx, root[i]);
      67     }
      68     int il, ir, ik;
      69     while(m--){
      70         scanf("%d%d%d", &il, &ir, &ik);
      71         int t = myfind(root[il-1], root[ir], ik, 1, idx);
      72         printf("%d
      ", a[t] );
      73     }
      74     return 0;
      75 }
      இ௰இ

    hduoj5919 Sequence II 2016ccpcchangchunj

    • 输入一个数组,有m次询问
    • 强制在线,每个询问(l,r),假如(l,r)有k个不同的数,要求输出第(k+1)/2个数的下标
    • 倒着从n~1遍历建树,因为每一次要更新两个,一个是i位置要加1,一个是pre[i]要减1
    • pre[i]是i位置上的数上一次出现的位置(倒着遍历)
    • 这样的话,相当于每次只是某个数第一次出现的地方是1,其他都是0,每个询问直接查询root[l]就行
    • 代码:
       1 #include <bits/stdc++.h>
       2 #define nmax 200100
       3 
       4 using namespace std;
       5 int n, m, cnt=0;
       6 int pos[nmax]={0}, a[nmax], pre[nmax], v[nmax*40], root[nmax], ls[nmax*40], rs[nmax*40];
       7 
       8 int build(int l, int r){
       9     int u=++cnt;
      10     v[u] = 0;
      11     if(l==r) return u;
      12     int mid = (l+r)>>1;
      13     ls[u] = build(l, mid);
      14     rs[u] = build(mid+1, r);
      15     return u;
      16 }
      17 
      18 void upd(int u, int k, int l, int r, int u2, int p){
      19     v[u2] = v[u]+p;
      20     if(l==r) return;
      21     int mid = (l+r)>>1 ;
      22     if(k<=mid) {
      23         rs[u2] = rs[u];
      24         ls[u2] = ++cnt;
      25         upd(ls[u], k, l, mid, ls[u2], p);
      26     }else{
      27         ls[u2] = ls[u];
      28         rs[u2] = ++cnt;
      29         upd(rs[u], k, mid+1, r, rs[u2], p);
      30     }
      31 }
      32 
      33 int getlen(int u, int l, int r, int l1, int r1){
      34     if(l1<=l && r1>=r) return v[u];
      35     int ans = 0;
      36     int mid = (l+r)>>1;
      37     if(l1 <= mid) ans += getlen(ls[u], l, mid, l1, r1);
      38     if(r1 > mid) ans += getlen(rs[u], mid+1, r, l1, r1);
      39     return ans;
      40 }
      41 
      42 int myfind(int u, int k, int l, int r){
      43     if(l==r) return l;
      44     int num = v[ ls[u] ];
      45     int mid = (l+r)>>1;
      46     if(k<=num) return myfind(ls[u], k, l, mid);
      47     else return myfind(rs[u], k-num, mid+1, r);
      48 }
      49 
      50 int main(){
      51     int kas;
      52     cin >> kas;
      53     for (int cas=1; cas<=kas; cas++) {
      54         cnt = 0;
      55         scanf("%d%d", &n, &m);
      56         for (int i=1; i<=n; i++) { scanf("%d", &a[i]); pos[ a[i] ] = 0; }
      57         for (int i=n; i>=1; i--) {
      58             pre[i] = pos[ a[i] ];
      59             pos[ a[i] ] = i;
      60         }
      61         build(1, n);
      62         root[n+1] = 1;
      63         for (int i=n; i>=1; i--) {
      64             root[i] = ++cnt;
      65             upd(root[i+1], i, 1, n, root[i], 1);
      66             if(pre[i]) {
      67                 int u = ++cnt;
      68                 upd(root[i], pre[i], 1, n, u, -1);
      69                 root[i] = u;
      70             }
      71         }
      72         printf("Case #%d:", cas);
      73         int il, ir, li, ri, t = 0, k;
      74         while(m--){
      75             scanf("%d%d", &il, &ir);
      76             li = min( (il+t)%n+1 , (ir+t)%n+1 );
      77             ri = max( (il+t)%n+1 , (ir+t)%n+1 );
      78             k = getlen(root[li], 1, n, li, ri);
      79             t = myfind(root[li], (k+1)/2, 1, n);
      80             printf(" %d", t);
      81         }
      82         printf("
      ");
      83     }
      84     return 0;
      85 }
      (*Φ皿Φ*)
  • 相关阅读:
    iOS之蓝牙开发—CoreBluetooth详解
    iOS-GCD使用详解
    iOS—Mask属性的使用
    idea导入eclipse中的maven项目
    SQL Server 查找字符串中指定字符出现的次数
    lLinux的常用命令
    从excel表中生成批量SQL
    ORA-00911: invalid character 错误解决
    sqlserver sp_who2和inputbuffer的使用,连接数
    如果存在这个表,则删除这个表的sql
  • 原文地址:https://www.cnblogs.com/jiecaoer/p/11928443.html
Copyright © 2011-2022 走看看