主席树几道题目

原创 2013年12月04日 16:54:57


主要参考cxlove博客kuangbin博客

感觉主席树和划分树有类似之处,分治的思想


Poj2104 主席树静态区间第k值

以每个位置为起点,建立一棵主席树,保存后缀区间的情况。

每个节点保存的是该后缀在相应区间数的个数

const int MAXN = 100010;
const int MOD = 1000000;
int a[MAXN], t[MAXN];
int T[MAXN * 30], lson[MAXN * 30],rson[MAXN * 30], c[MAXN * 30];
int n, sz, q;
int tot;
void init_hash()
{
   FE(i, 1, n) t[i] = a[i];
   sort(t + 1, t + 1 + n);
   sz = unique(t + 1, t + 1 + n) - t - 1;
}
int build(int l, int r)
{
   int rt = tot++;
   c[rt] = 0;
   if (l != r)
    {
       int m = (l + r) >> 1;
       lson[rt] = build(l, m);
       rson[rt] = build(m + 1, r);
    }
   return rt;
}
 
int hash(int x)
{
    returnlower_bound(t + 1, t + 1 + n, x) - t;
}
 
int update(int rt, int pos, int val)
{
   int new_rt = tot++;
   int tmp = new_rt;
   c[new_rt] = c[rt] + val;
   int l = 1, r = sz;
   while (l < r)
    {
       int m = (l + r) >> 1;
       if (pos <= m)
       {
           lson[new_rt] = tot++; rson[new_rt] = rson[rt];
           new_rt = lson[new_rt]; rt = lson[rt];
           r = m;
       }
       else
       {
           rson[new_rt] = tot++; lson[new_rt] = lson[rt];
           new_rt = rson[new_rt]; rt = rson[rt];
           l = m + 1;
       }
       c[new_rt] = c[rt] + val;
    }
   return tmp;
}
 
int query(int L, int  R, int k)
{
   int l = 1, r = sz;
   while (l < r)
    {
       int m = (l + r) >> 1;
       if (c[lson[L]] - c[lson[R]] >= k)
       {
           L = lson[L]; R = lson[R];
           r = m;
       }
       else
       {
           k -= c[lson[L]] - c[lson[R]];///!!!
           L = rson[L]; R = rson[R];
           l = m + 1;
       }
    }
   return l;
}
 
int main()
{
   int x, y, z;
   while (cin >> n >> q)
    {
       tot = 0;
       FE(i, 1, n) RI(a[i]);
       init_hash();
       T[n + 1] = build(1, sz);///!!!
       FED(i, n, 1)
       {
           int pos = hash(a[i]);
           T[i] = update(T[i + 1], pos, 1);
       }
       while (q--)
       {
           RIII(x, y, z);
           printf("%d\n", t[query(T[x], T[y + 1], z)]);
       }
    }
}


spoj EQUERY 静态区间,区间中不同值的数的个数

对于每一个起始位置,都建立一棵主席树

从后往前更新,更新的时候就是在next位置先减掉,然后更新在当前位置。

主席树又称为可持久化线段树,其本质上是保存了所有的历史信息。

也可以理解为多棵线段树,在更新的时候,充分共同利用历史信息

对于点更新来说,更新的总是某一棵子树,另外一棵子树,则指向原来的结点即可。

可是即使如此,主席树还是需要大量的空间。

const int MAXN = 100010;
const int MOD = 1000000;
 
int a[MAXN], t[MAXN];
int T[MAXN * 60], lson[MAXN * 60],rson[MAXN * 60], c[MAXN * 60];
int n, q;
int tot;
map<int, int> mp;
 
int build(int l, int r)
{
   int rt = tot++;
   c[rt] = 0;
   if (l != r)
    {
       int m = (l + r) >> 1;
       lson[rt] = build(l, m);
        rson[rt] = build(m + 1, r);
    }
   return rt;
}
 
int update(int rt, int pos, int val)
{
   int new_rt = tot++;
   int tmp = new_rt;
   c[new_rt] = c[rt] + val;
   int l = 1, r = n;
   while (l < r)
    {
       int m = (l + r) >> 1;
       if (pos <= m)
       {
           lson[new_rt] = tot++; rson[new_rt] = rson[rt];
           new_rt = lson[new_rt]; rt = lson[rt];
           r = m;
       }
       else
       {
           rson[new_rt] = tot++; lson[new_rt] = lson[rt];
           new_rt = rson[new_rt]; rt = rson[rt];
           l = m + 1;
       }
       c[new_rt] = c[rt] + val;
    }
   return tmp;
}
 
int query(int rt, int pos)
{
   int ans = 0;
   int l = 1, r = n;
   while (l < r)///(pos < r)
    {
       int m = (l + r) >> 1;
 
       if (pos <= m)
       {
           rt = lson[rt];
           r = m;
       }
       else
       {
           ans += c[lson[rt]];
           rt = rson[rt];
           l = m + 1;
       }
    }
   return ans + c[rt];
}
 
int main()
{
   int x, y, z;
   while (cin >> n)
    {
       tot = 0;
       FE(i, 1, n) RI(a[i]);
       mp.clear();
       T[n + 1] = build(1, n);
       FED(i, n, 1)
       {
           if (mp.find(a[i]) == mp.end())
           {
                T[i] = update(T[i + 1], i, 1);
           }
           else
           {
                int tmp = update(T[i + 1],mp[a[i]], -1);
                T[i] = update(tmp, i, 1);
           }
           mp[a[i]] = i;
       }
       cin >> q;
       while (q--)
        {
           RII(x, y);
           printf("%d\n", query(T[x], y));
       }
    }
}
 

zoj 2112 Dynamic Rankings 动态第k值,树状数组套线段树


、、、

主席树专题

最近在学主席树所以开个坑。 席树发明者fotile,后人也称其为fotile主席。同时主席树也被叫做可持续化线段树等,因为主席树这个名字显得高贵冷艳,所以现在大部分人都叫它主席树。——引子 无修...
  • cx_lzx
  • cx_lzx
  • 2017年04月15日 11:21
  • 333

主席树小结

简直卧槽了,充满RE的一天,没有太完成目标,算上昨天刷的一道主席树一共五道,算是入门了吧。 主席树可以认为是一种前缀和,表示的是每一个数出现的次数(当然必须要离散化),一种类似线段树的建法,为了节省...
  • u012288458
  • u012288458
  • 2015年08月05日 23:43
  • 2417

对主席树的一点理解 -- 例题POJ 2104

断断续续看了许久的主席树,简单记录一下。 什么样的题目用主席树呢,比如POJ 2104 求区间第K大的数是谁? 当时做这个题时,感觉分块+二分可以搞,就写了好久,改了好久,始终TLE,还是学学主席...
  • aozil_yang
  • aozil_yang
  • 2017年03月22日 21:50
  • 451

【BZOJ 2653】middle 主席树好题推荐

谈谈这一道题的最强烈的感受在于,我的主席树入门是经典题目区间第k大树查询(当然,因为poj上不会强制在线,还用树套树和整体二分写过那道题),因此,对于主席树的理解仅仅是一个区间历史版本维护的理解,即类...
  • pbihao
  • pbihao
  • 2016年12月25日 21:36
  • 136

主席树 专题

poj2104poj 2104 静态区间第k大,没有修改,所以时间是O(nlogn),空间也是O(nlogn)静态区间第k大,没有修改,所以时间是O(nlogn),空间也是O(nlogn) 模版,...
  • Miracle_ma
  • Miracle_ma
  • 2016年09月28日 23:39
  • 389

POJ 2104 K-th Number 主席树模板题

题目:http://poj.org/problem?id=2104 题意:给定一个长度为n的无序数组,然后有m组询问l r k,求区间[l,r]中的第k大数 思路:以前用划分树做过,现在学习主席树...
  • discreeter
  • discreeter
  • 2016年09月02日 15:36
  • 527

主席树

先不瞎说什么,直接上模板题:P3834 【模板】可持久化线段树 1(主席树) 题目背景 这是个非常经典的主席树入门题——静态区间第K小 数据已经过加强,请使用主席树。同时请注...
  • lvmaooi
  • lvmaooi
  • 2018年01月29日 16:43
  • 11

系统分析师考试通过了,一点感想

第一次考试是在2006年5月份,结果被吓倒了,考试都没敢去。第二次因为感觉没有退路,反而孤注一掷,两个月内坚持把几本参考书看完了,同时在网上把一些新技术熟悉了一遍。尤其是SOA恰好给赶上了。因而险过系...
  • yuanbocsut
  • yuanbocsut
  • 2007年01月06日 12:22
  • 1372

java 笔试之继承基础(看看你能做对几道题)初学者不要小看啊

先笔试,全是基础题,共30道简笔题, 1. abstract class Name {  private String name;  public abstract boolean isStu...
  • a564663276
  • a564663276
  • 2013年05月20日 21:40
  • 3102

主席树几道题目

主要参考cxlove博客kuangbin博客 感觉主席树和划分树有类似之处,分治的思想 Poj2104 主席树静态区间第k值 以每个位置为起点,建立一棵主席树,保存后缀区间的情况。 每个节点保存的...
  • guognib
  • guognib
  • 2013年12月04日 16:54
  • 1360
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:主席树几道题目
举报原因:
原因补充:

(最多只允许输入30个字)