带修改的区间第k大

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1112

提高代码能力。。。

方法一:

线段树套平衡树,时间:O(m*lgn*lgn*lgn),空间:O(n*lgn)。

<pre name="code" class="cpp">#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;

const int MAXN(50010);

template<typename T>
bool checkmin(T &a, const T &b){
    return b < a? (a = b, true): false;
}
template<typename T>
bool checkmax(T &a, const T &b){
    return b > a? (a = b, true): false;
}

struct RAND{
    int rn[MAXN], si, n;
    void init(int n){
        this->n = n;
        srand(2357);
        for(int i = 0; i < n; ++i) rn[i] = rand();
        si = 0;
    }
    int query(){
        if(si >= n) si -= n;
        return rn[si++];
    }
} ra;

struct NODE1{
    int ke, b, si;
    NODE1 *ch[2];
} *NIL1;

struct POOL1{
    NODE1 pool[MAXN*19], *last;
    void init(){
        last = pool;
    }
    NODE1 *all(int k){
        last->ch[0] = last->ch[1] = NIL1;
        last->ke = k;
        last->b = ra.query();
        last->si = 1;
        return last++;
    }
} pool1;

inline void rep(NODE1 *rt){
    if(rt == NIL1) return;
    rt->si = rt->ch[0]->si+rt->ch[1]->si+1;
}

void rot(NODE1 *&rt, int f){
    NODE1 *s = rt->ch[f];
    rt->ch[f] = s->ch[!f];
    s->ch[!f] = rt;
    rep(rt);
    rep(s);
    rt = s;
}

void Insert(NODE1 *&rt, int k){
    if(rt == NIL1){
        rt = pool1.all(k);
        return;
    }
    int t = (k >= rt->ke);
    Insert(rt->ch[t], k);
    if(rt->ch[t]->b > rt->b) rot(rt, t);
    rep(rt);
}

void Erase(NODE1 *&rt, int k){
    if(rt->ke == k){
        if(rt->ch[0] == NIL1 || rt->ch[1] == NIL1){
            rt = rt->ch[rt->ch[0] == NIL1];
//            rep(rt);
            return;
        }
        int t = rt->ch[0]->b < rt->ch[1]->b;
        rot(rt, t);
        Erase(rt->ch[!t], k);
        rep(rt);
        return;
    }
    Erase(rt->ch[k >= rt->ke], k);
    rep(rt);
}

int Lower_bound(NODE1 *rt, int k){
    if(rt == NIL1) return 0;
    if(k <= rt->ke) return Lower_bound(rt->ch[0], k);
    return rt->ch[0]->si+1+Lower_bound(rt->ch[1], k);
}

int arr[MAXN];
NODE1 *srt[MAXN << 2];

int query(int ql, int qr, int k, int l, int r, int rt){
    if(srt[rt] == 0){
        srt[rt] = NIL1;
        for(int i = l; i <= r; ++i) Insert(srt[rt], arr[i]);
    }
    if(ql <= l && qr >= r) return Lower_bound(srt[rt], k);
    int m = (l+r)/2, ret = 0;
    if(ql <= m) ret += query(ql, qr, k, l, m, rt << 1); //小心,不要把qr写成m,考虑[ql, qr]包含于左子树的情况
    if(qr > m) ret += query(ql, qr, k, m+1, r, (rt << 1)|1); //小心,不要把ql写成m+1,考虑[ql, qr]包含于右子树的情况
    return ret;
}

void update(int loc, int k, int l, int r, int rt){
    if(srt[rt] == 0){
        srt[rt] = NIL1;
        for(int i = l; i <= r; ++i) Insert(srt[rt], arr[i]);
    }
    if(l <= loc && loc <= r){
        Erase(srt[rt], arr[loc]);
        Insert(srt[rt], k);
    }
    if(l == r) return;
    int m = (l+r)/2;
    if(loc <= m) update(loc, k, l, m, rt << 1);
    else update(loc, k, m+1, r, (rt <<1)|1);
}

int main(){
    ra.init(50000);
    NIL1 = new NODE1();
    NIL1->ch[0] = NIL1->ch[1] = NIL1;
    NIL1->b = -1;
    NIL1->si = 0;
    int TC;
    scanf("%d", &TC);
    while(TC--){
        int n, M, a, b, c;
        char s[2];
        scanf("%d%d", &n, &M);
        pool1.init();
        memset(srt, 0, sizeof(srt));
        int mi = 1000000001, mx = -1;
        for(int i = 1; i <= n; ++i){
            scanf("%d", arr+i);
            checkmin(mi, arr[i]);
            checkmax(mx, arr[i]);
        }
        for(int i = 0; i < M; ++i){
            scanf("%s", s);
            if(s[0] == 'Q'){
                scanf("%d%d%d", &a, &b, &c);
                int l = mi, r = mx, m, t;
                while(l <= r){
                    m = (l+r)/2;
                    t = query(a, b, m, 1, n, 1);
                    if(t < c) l = m+1;
                    else r = m-1;
                }
                printf("%d\n", l-1);
            }else{
                scanf("%d%d", &a, &b);
                update(a, b, 1, n, 1);
                arr[a] = b;
                checkmin(mi, b);
                checkmax(mx, b);
            }
        }
    }
    return 0;
}

 方法二: 
 

分块处理,时间:O(m*sqrtn*lgn*lgn),空间:O(n)

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>

using namespace std;

const int MAXN(50010);

template<typename T>
bool checkmin(T &a, const T &b){
    return b < a? (a = b, true): false;
}
template<typename T>
bool checkmax(T &a, const T &b){
    return b > a? (a = b, true): false;
}

int ar1[MAXN], ar2[MAXN];

int main(){
    int TC;
    scanf("%d", &TC);
    while(TC--){
        int n, M, mi = 1000000001, mx = -1;
        scanf("%d%d", &n, &M);
        for(int i = 0; i < n; ++i){
            scanf("%d", ar1+i);
            ar2[i] = ar1[i];
            checkmin(mi, ar1[i]);
            checkmax(mx, ar1[i]);
        }
        int sq = sqrt(n+1.);
        for(int i = 0; i < n; i += sq) sort(ar2+i, ar2+min(i+sq, n));
        char s[2];
        int a, b, c;
        for(int i = 0; i < M; ++i){
            scanf("%s", s);
            if(s[0] == 'Q'){
                scanf("%d%d%d", &a, &b, &c);
                --a, --b;
                int li = a/sq, ri = b/sq;
                int t, m, l = mi, r = mx;
                while(l <= r){
                    m = (l+r)/2;
                    t = 0;
                    if(li == ri){
                        for(int j = a; j <= b; ++j)
                            if(ar1[j] < m)
                                ++t;
                    } else{
                        for(int j = a; j < sq*(li+1); ++j) if(ar1[j] < m) ++t;
                        for(int j = li+1; j < ri; ++j) t += lower_bound(ar2+j*sq, ar2+(j+1)*sq, m)-(ar2+j*sq);
                        for(int j = sq*ri; j <= b; ++j) if(ar1[j] < m) ++t;
                    }
                    if(t < c) l = m+1;
                    else r = m-1;
                }
                printf("%d\n", l-1);
            } else{
                scanf("%d%d", &a, &b);
                --a;
                ar1[a] = b;
                checkmin(mi, b);
                checkmax(mx, b);
                int li = (a/sq)*sq, ri = min((a/sq+1)*sq, n);
                for(int j = li; j < ri; ++j) ar2[j] = ar1[j];
                sort(ar2+li, ar2+ri);
            }
        }
    }
    return 0;
}

方法三:

树状数组套函数式线段树,时间:O((n+m)*lgn*lgn),空间:O((n+m)*lgn*lgn)。

超内存。。。


方法四:

值域线段树套下标线段树,时间:O((n+m)*lgn*lgn),空间:O((n+m)*lgn*lgn)。

超内存。。。,存下代码。

struct NODE{
	int dat;
	NODE *ls, *rs;
	NODE(){}
	NODE(int d_, NODE *ls_, NODE *rs_) :dat(d_), ls(ls_), rs(rs_){}
	void push_up(){
		dat = 0;
		if (ls) dat += ls->dat;
		if (rs) dat += rs->dat;
	}
};

void update(int l, int r, NODE *&p, int id, int v){
	if (p == 0) p = new NODE(0, 0, 0);
	if (l == r) {
		p->dat += v;
		return;
	}
	int m = (l + r) / 2;
	if (id <= m) update(l, m, p->ls, id, v);
	else update(m + 1, r, p->rs, id, v);
	p->push_up();
}

int query(int l, int r, NODE *&p, int ql, int qr){
	if (p == 0)
		return 0;
	if (ql <= l && qr >= r) return p->dat;
	int m = (l + r) / 2, ret = 0;
	if (ql <= m) ret += query(l, m, p->ls, ql, qr);
	if (qr > m) ret += query(m + 1, r, p->rs, ql, qr);
	return ret;
}

struct NODE1{
	NODE *dat;
	NODE1 *ls, *rs;
	NODE1(){}
	NODE1(NODE *d_, NODE1 *ls_, NODE1 *rs_): dat(d_), ls(ls_), rs(rs_){}
};

vector<int> rec[MAXM];

int N;

inline void pre(NODE1 *&p, int l, int r){
	if (p == 0){
		p = new NODE1(0, 0, 0);
		for (int i = l; i <= r; ++i)
		for (int j = 0; j < rec[i].size(); ++j)
			update(0, N - 1, p->dat, rec[i][j], 1);
	}
}

void update1(int l, int r, NODE1 *&p, int id, int v, int v1){
	pre(p, l, r);
	update(0, N - 1, p->dat, id, v1);
	if (l == r) return;
	int m = (l + r) / 2;
	if (v <= m) update1(l, m, p->ls, id, v, v1);
	else update1(m + 1, r, p->rs, id, v, v1);
}

int query1(int l, int r, NODE1 *&p, int ql, int qr, int K){
	if (l == r)
		return l;
	pre(p, l, r);
	int m = (l + r) / 2;
	pre(p->ls, l, m);
	int temp = query(0, N - 1, p->ls->dat, ql, qr);
	if (temp >= K)
		return query1(l, m, p->ls, ql, qr, K);
	else{
		pre(p->rs, m + 1, r);
		return query1(m + 1, r, p->rs, ql, qr, K-temp);
	}
}

int arr[MAXN];
int buf[MAXM], bn;
char op[10001][2];
int arg[10001][3];

int main(){
	int TC;
	scanf("%d", &TC);
	while (TC--){
		bn = 0;
		int n, m;
		scanf("%d%d", &n, &m);
		N = n;
		for (int i = 0; i < n; ++i){
			scanf("%d", arr + i);
			buf[bn++] = arr[i];
		}
		for (int i = 0; i < m; ++i){
			scanf("%s", op + i);
			if (op[i][0] == 'Q'){
				scanf("%d%d%d", arg[i], arg[i] + 1, arg[i] + 2);
			}
			else{
				scanf("%d%d", arg[i], arg[i] + 1);
				buf[bn++] = arg[i][1];
			}
		}
		sort(buf, buf + bn);
		bn = unique(buf, buf + bn) - buf;
		for (int i = 0; i < bn; ++i) rec[i].clear();
		for (int i = 0; i < n; ++i){
			arr[i] = lower_bound(buf, buf + bn, arr[i]) - buf;
			rec[arr[i]].push_back(i);
		}
		for (int i = 0; i < m; ++i){
			if (op[i][0] == 'Q'){
				--arg[i][0];
				--arg[i][1];
			}
			else{
				--arg[i][0];
				arg[i][1] = lower_bound(buf, buf + bn, arg[i][1]) - buf;
			}
		}

		NODE1 *rt = 0;
		for (int i = 0; i < m; ++i){
			if (op[i][0] == 'Q'){
				if (i < 1)
					printf("%d\n", buf[query1(0, bn - 1, rt, arg[i][0], arg[i][1], arg[i][2])]);
				else{
					printf("123\n");
				}
			}
			else{
				if (i < 0){
					update1(0, bn - 1, rt, arg[i][0], arr[arg[i][0]], -1);
					update1(0, bn - 1, rt, arg[i][0], arg[i][1], 1);
					arr[arg[i][0]] = arg[i][1];
				}
			}
		}
	}
	return 0;
}



你可能感兴趣的:(带修改的区间第k大)