BZOJ 3065 带插入区间第K小值

题目描述

Description

从前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i]。跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴。这时跳蚤国王决定理性愉悦一下,查询区间k小值。他每次向它的随从伏特提出这样的问题: 从左往右第x个到第y个跳蚤中,a[i]第k小的值是多少。
这可难不倒伏特,他在脑袋里使用函数式线段树前缀和的方法水掉了跳蚤国王的询问。
这时伏特发现有些跳蚤跳久了弹跳力会有变化,有的会增大,有的会减少。
这可难不倒伏特,他在脑袋里使用树状数组套线段树的方法水掉了跳蚤国王的询问。(orz 主席树)
这时伏特发现有些迟到的跳蚤会插入到这一行的某个位置上,他感到非常生气,因为……他不会做了。
请你帮一帮伏特吧。
快捷版题意:带插入、修改的区间k小值在线查询。

Input

第一行一个正整数n,表示原来有n只跳蚤排成一行做早操。
第二行有n个用空格隔开的非负整数,从左至右代表每只跳蚤的弹跳力。
第三行一个正整数q,表示下面有多少个操作。
下面一共q行,一共三种操作对原序列的操作:(假设此时一共m只跳蚤)

  1. Q x y k: 询问从左至右第x只跳蚤到从左至右第y只跳蚤中,弹跳力第k小的跳蚤的弹跳力是多少。
    (1 <= x <= y <= m, 1 <= k <= y - x + 1)
  2. M x val: 将从左至右第x只跳蚤的弹跳力改为val。
    (1 <= x <= m)
  3. I x val: 在从左至右第x只跳蚤的前面插入一只弹跳力为val的跳蚤。即插入后从左至右第x只跳蚤是我刚插入的跳蚤。
    (1 <= x <= m + 1)

为了体现在线操作,设lastAns为上一次查询的时候程序输出的结果,如果之前没有查询过,则lastAns = 0。
则输入的时候实际是:
Q _x _y _k ------> 表示 Q _x^lastAns _y^lastAns _k^lastAns
M _x _val ------> 表示 M _x^lastAns _val^lastAns
I _x _val ------> 表示 I _x^lastAns _val^lastAns
简单来说就是操作中输入的整数都要异或上一次询问的结果进行解码。

(祝Pascal的同学早日转C++,就不提供pascal版的描述了。)

Sample Input

10
10 5 8 28 0 19 2 31 1 22 
30
I 6 9
M 1 11
I 8 17
M 1 31
M 6 26
Q 2 7 6
I 23 30
M 31 7
I 22 27
M 26 18
Q 26 17 31
I 5 2
I 18 13
Q 3 3 3
I 27 19
Q 23 23 30
Q 5 13 5
I 3 0
M 15 27
Q 0 28 13
Q 3 29 11
M 2 8
Q 12 5 7
I 30 19
M 11 19
Q 17 8 29
M 29 4
Q 3 0 12
I 7 18
M 29 27

Sample Output

28
2
31
0
14
15
14
27
15
14

题目大意

略.

题解

替罪羊树模板题.
用一棵替罪羊树维护序列, 每个节点上开一棵线段树, 维护以这个点为根的子树下的所有权值.
考虑以下操作:

  • 插入: 直接在替罪羊树上插入即可, 正常重建.
  • 修改: 直接修改.
  • 查询: 这个比较麻烦. 我的做法是在替罪羊树上找到所有被这个区间覆盖的点, 分为以下两类
    • 这个点以及以它为根的子树都被题目所求区间包含, 则将这个点上的线段树扔进vector中;
    • 这个点被区间包含, 但并非以它为根的子树都被包含, 则在一棵另开的线段树上插入这个点对应的序列上的权值, 并递归其子树.

 在得到的最多\(\log n\)棵线段树上二分即可

这样的做法是可以保证时空复杂度均为\(n \log^2 n\), 还是可以接受的.
注意空间释放的问题, 我只会写动态的指针式写法, 有些大佬说可以用数组静态模拟, 但我没想懂怎么释放内存, 总之就是不会.
代码跑得很慢, 可能是频繁申请 / 释放空间导致的吧

#include <cstdio>
#include <cctype>
#include <vector>
#include <algorithm>
  
namespace Zeonfai
{
    inline int getInt()
    {
        int a = 0, sgn = 1;
        char c;
         
        while(! isdigit(c = getchar()))
            if(c == '-')
                sgn *= -1;
         
        while(isdigit(c))
            a =  a * 10 + c - '0', c = getchar();
         
        return a * sgn;
    }
     
    inline char getChar()
    {
        char c;
         
        while(! isgraph(c = getchar()));
         
        return c;
    }
     
    inline void print(int a)
    {
        if(! a)
            return;
         
        print(a / 10);
        putchar(a % 10 + '0');
    }
     
    inline void println(int a)
    {
        if(a < 0)
            putchar('-'), a *= -1;
         
        if(a == 0)
            putchar('0');
         
        print(a);
        putchar('\n');
    }
}
  
const int N = 35000, Q = 35000, BND = 70000;
const double ALPH = 0.75;
std::vector<int> cpy;
  
struct segmentTree
{
    struct node
    {
        node* suc[2];
        int sum;
      
        inline node()
        {
            suc[0] = suc[1] = NULL;
            sum = 0;
        } 
    };
     
    node* rt;
     
    inline segmentTree()
    {
        rt = NULL;
    }
  
    node* modify(node* u, int opt, int L, int R, int w)
    {
        if(u == NULL)
            u = new node;
  
        u->sum += opt;
  
        if(L ^ R)
        {
            int mid = L + R >> 1;
  
            if(w <= mid)
                u->suc[0] = modify(u->suc[0], opt, L, mid, w);
            else
                u->suc[1] = modify(u->suc[1], opt, mid + 1, R, w);
        }
  
        return u;
    }

    inline void modify(int pos, int opt)
    {
    	rt = modify(rt, opt, 0, BND, pos);
    }
  
    inline void insert(int w)
    {
        rt = modify(rt, 1, 0, BND, w);
    }
     
    void clear(node *u)
    {
        for(int i = 0; i < 2; ++ i)
            if(u->suc[i] != NULL)
                clear(u->suc[i]);
         
        delete u;
    }
     
    inline void clear()
    {
    	if(rt != NULL)
        	clear(rt), rt = NULL;
    }

    inline void Delete()
    {
    	clear();
    	delete this;
    }
};

segmentTree sgt; 
std::vector<segmentTree::node*> nd, _nd;
  
struct scapegoatTree
{
    struct node
    {
        node *suc[2];
        int sz, w;
        segmentTree *rec;
  
        inline node(int _w)
        {
            sz = 0, w = _w;
            suc[0] = suc[1] = NULL;
            rec = new segmentTree;
        }
  
        inline int check()
        {
            int sucSz[2] = {0, 0};
  
            for(int i = 0; i < 2; ++ i)
                if(suc[i] != NULL)
                    sucSz[i] = suc[i]->sz;
  
            return std::max(sucSz[0], sucSz[1]) > sz * ALPH;
        }
    };
  
    node *rt;
  
    node* build(int L, int R)
    {
        int mid = L + R >> 1;
        node *u = new node(cpy[mid]);
  
        if(L < mid)
            u->suc[0] = build(L, mid - 1);
  
        if(R > mid)
            u->suc[1] = build(mid + 1, R);
  
        for(int i = L; i <= R; ++ i)
            u->rec->insert(cpy[i]), ++ u->sz;
  
        return u;
    }
  
    int flg;
  
    void DFS(node* u)
    {
        u->rec->Delete();

    	if(u->suc[0] != NULL)
    		DFS(u->suc[0]);

        cpy.push_back(u->w);

        if(u->suc[1] != NULL)
        	DFS(u->suc[1]);
         
        delete u;   
    }
  
    inline node* rebuild(node *u)
    {
        cpy.clear();
        DFS(u);
        u = build(0, cpy.size() - 1);
        flg = 1;
        return u;
    }
  
    node* insert(node* u, int pos, int w)
    {
    	int tmp = u == NULL || u->suc[0] == NULL ? 0 : u->suc[0]->sz;

        if(u == NULL)
            u = new node(w);
        else if(pos <= tmp + 1)
            u->suc[0] = insert(u->suc[0], pos, w);
        else
            u->suc[1] = insert(u->suc[1], pos - tmp - 1, w);
  
        ++ u->sz;
        u->rec->insert(w);
  
        if(u->check())
            u = rebuild(u);
  
        return u;
    }
  
    inline void insert(int pos, int w)
    {
        flg = 0;
        rt = insert(rt, pos, w);
    }
  
    void get(node* u, int L, int R)
    {
        if(L == 1 && R == u->sz)
        {
            nd.push_back(u->rec->rt);
            return;
        }
         
        int tmp = u->suc[0] == NULL ? 0 : u->suc[0]->sz; 

        if(tmp + 1 >= L && tmp + 1 <= R)
        	sgt.insert(u->w);
         
        if(u->suc[0] != NULL && L <= tmp)
            get(u->suc[0], L, std::min(tmp, R));
         
        if(u->suc[1] != NULL && R >= tmp + 2)
            get(u->suc[1], std::max(L, tmp + 2) - tmp - 1, R - tmp - 1);
    }
  
    inline int query(int x, int y, int k)
    {
        nd.clear();
        sgt.clear();
        get(rt, x, y);

        if(sgt.rt != NULL)
        	nd.push_back(sgt.rt);

        int L = 0, R = BND;
         
        while(L ^ R)
        {
            int cnt = nd.size(), sum = 0;
              
            for(int i = 0; i < cnt; ++ i)
                sum += nd[i]->suc[0] == NULL ? 0 : nd[i]->suc[0]->sum;
            
            _nd.clear();
         
            for(int i = 0; i < cnt; ++ i)
                if(nd[i]->suc[sum < k] != NULL)
                    _nd.push_back(nd[i]->suc[sum < k]);

            nd = _nd;
             
            if(sum >= k)
                R = (L + R) >> 1;
            else
                L = ((L + R) >> 1) + 1, k -= sum;
        }
         
        return L;
    }

    int modify(node* u, int pos, int w)
    {
    	int tmp = u->suc[0] == NULL ? 0 : u->suc[0]->sz;

    	if(pos == tmp + 1)
    	{
    		u->rec->modify(u->w, -1), u->rec->modify(w, 1);
    		int res = u->w;
    		u->w = w;
    		return res;
    	}

    	int res;

    	if(u->suc[0] != NULL && pos <= u->suc[0]->sz)
    		res = modify(u->suc[0], pos, w);
    	else
    		res = modify(u->suc[1], pos - tmp - 1, w);

    	u->rec->modify(res, -1), u->rec->modify(w, 1);
    	return res;
    }

    inline void modify(int pos, int w)
    {
    	modify(rt, pos, w);
    }
}seq;
  
int main()
{
	#ifndef ONLINE_JUDGE
	freopen("BZOJ3065.in", "r", stdin);
	freopen("BZOJ3065.out", "w", stdout);
	#endif

    using namespace Zeonfai;
  
    int n = getInt();
  
    for(int i = 0; i < n; ++ i)
        cpy.push_back(getInt());
  
    seq.rt = seq.build(0, n - 1);
    int Q = getInt(), lst = 0;
  
    for(int i = 0; i < Q; ++ i)
    {
        char opt = getChar();
  
        if(opt == 'I')
        {
            int pos = getInt() ^ lst, w = getInt() ^ lst;
            seq.insert(pos, w);
        }
        else if(opt == 'Q')
        {
            int x = getInt() ^ lst, y = getInt() ^ lst, k = getInt() ^ lst;
            println(lst = seq.query(x, y, k));
        }
        else if(opt == 'M')
        {
        	int x = getInt() ^ lst, w = getInt() ^ lst;
        	seq.modify(x, w);
        }
    }
}

posted @ 2017-06-29 21:27  Zeonfai  阅读(275)  评论(0编辑  收藏  举报