BZO3065 带插入区间K小值

[]

What a problem! I thought I had to spend more than a week to solve it. Fortunately, it didn't cost me so much time.


[Solution]

I thought of segment tree + balanced tree + splay at first. Use segment tree to refrence the value, use sbt to modify the position, and it must be dynamic where splay is used. It's log^3(n), which would certainly TLE!

Then I tried scopegoat tree + dynamic segment tree. It's log^2(n), although I have never coded scopegoat tree before.

Scopegoat tree is a balanced tree. After each insert operation, check every node on the path, and choose the most unbalanced one. If it's sort of unbalanced, simply rebuild the whole sub-tree. It can be proved that the time complex is still O(n lgn), but I don't know how to prove it. Maybe imagine.

Then a trash recycle system is in need to prevent from MLE. After trying a long, I used the same strategy as that I used in Sequence(NOI2014).


[Code]

So long and ugly and slow!

#include <cstdio>
#include <cctype>
#include <memory.h>
#include <queue>
#include <algorithm>

using namespace std;

int nextInt() {
	int d, s = 0;
	do
		d = getchar();
	while (!isdigit(d));
	do
		s = s * 10 + d - 48, d = getchar();
	while (isdigit(d));
	return s;
}

const int maxn = 70009;
const int maxl = 57;
const int pssz = 2000000;

struct seg {
	int v, c;
	seg *ls, *rs;
};

#define von(p) ((p)?(p->v):0)
#define lson(p) ((p)?(p->ls):0)
#define rson(p) ((p)?(p->rs):0)

struct segtree {
	seg *sp, *can[pssz];
	int tcan, csp;
	void expTrash(seg* p) {
		if (p-> ls) {
			p-> ls-> c --;
			if (!p-> ls-> c)
				can[tcan ++] = p-> ls;
		}
		if (p-> rs) {
			p-> rs-> c --;
			if (!p-> rs-> c)
				can[tcan ++] = p-> rs;
		}
	}
	seg* newNode() {
		if (tcan) {
			seg* r = can[-- tcan];
			expTrash(r);
			return r;
		}
		else if (csp)
			return -- csp, ++ sp;
		else
			return csp = pssz, sp = new seg[pssz];
	}
	void init() {
		tcan = 0;
		csp = 0;
	}
	void recycle(seg* p) {
		if (!p)
			return;
		else if (!p-> c) {
			can[tcan ++] = p;
		}
		else if (p-> c < 0)
			puts("recycle error");
	}
	seg* chg(seg* q, int p0, int v0) {
		seg *s = newNode(), *p = s;
		int l = 0, r = maxn;
		while (l < r) {
			p-> v = von(q) + v0;
			p-> c = 1;
			int mid = (l + r) >> 1;
			if (p0 <= mid) {
				p-> rs = rson(q);
				if (p-> rs)
					p-> rs-> c ++;
				q = lson(q);
				p-> ls = newNode();
				p = p-> ls;
				r = mid;
			}
			else {
				p-> ls = lson(q);
				if (p-> ls)
					p-> ls-> c ++;
				q = rson(q);
				p-> rs = newNode();
				p = p-> rs;
				l = mid + 1;
			}
		}
		p-> v = von(q) + v0;
		p-> c = 1;
		p-> ls = 0;
		p-> rs = 0;
		return s;
	}
	seg* merge(seg* p, seg* q, int l = 0, int r = maxn) {
		if (!p && !q)
			return 0;
		if (!p) {
			q-> c ++;
			return q;
		}
		else if (!q) {
			p-> c ++;
			return p;
		}
		else {
			seg* s = newNode();
			s-> v = von(p) + von(q);
			s-> c = 1;
			if (l < r) {
				int mid = (l + r) >> 1;
				s-> ls = merge(lson(p), lson(q), l, mid);
				s->	rs = merge(rson(p), rson(q), mid + 1, r);
			}
			return s;
		}
	}
};

segtree sgt;

const double balanceConst = 0.75;

struct scapegoattree {
	int rt, ls[maxn], rs[maxn], sz[maxn], vl[maxn], buf[maxn], cbuf, tn;
	seg* sr[maxn];
	void update(int p) {
		sz[p] = sz[ls[p]] + sz[rs[p]] + 1;
		sr[p] = sgt. merge(sr[ls[p]], sr[rs[p]]);
		seg* sold = sr[p];
		sr[p] = sgt. chg(sr[p], vl[p], 1);
		sgt. recycle(sold);
	}
	void travel(int p) {
		if (!p)
			return;
		travel(ls[p]);
		buf[++ cbuf] = p;
		if (sr[p]) {
			sr[p]-> c = 0;
			sgt. recycle(sr[p]);
		}
		travel(rs[p]);
	}
	int rebuild(int p) {
		cbuf = 0;
		travel(p);
		return build(1, cbuf);
	}
	inline double balanceVal(int p) {
		return (double)(max(sz[ls[p]], sz[rs[p]])) / (double)sz[p];
	}
	void init() {
		tn = 0;
		rt = 0;
		sz[0] = 0;
		sr[0] = 0;
	}
	int addBuf(int v0) {
		int p = ++ tn;
		vl[p] = v0;
		sr[p] = 0;
		buf[++ cbuf] = p;
		return p;
	}
	int build(int l, int r) {
		if (l > r)
			return 0;
		int mid = (l + r) >> 1;
		int p = buf[mid];
		ls[p] = build(l, mid - 1);
		rs[p] = build(mid + 1, r);
		update(p);
		return p;
	}
	void build() {
		rt = build(1, cbuf);
	}
	void change(int p0, int v0) {
		int p = rt, rp[maxl], trp = 0, vo;
		while (p) {
			rp[++ trp] = p;
			seg* sold = sr[p];
			sr[p] = sgt. chg(sr[p], v0, 1);
			sold-> c --;
			sgt. recycle(sold);
			if (sz[ls[p]] + 1 == p0) {
				vo = vl[p];
				vl[p] = v0;
				break;
			}
			else if (sz[ls[p]] >= p0)
				p = ls[p];
			else
				p0 -= sz[ls[p]] + 1, p = rs[p];
		}
		for (int i = 1; i <= trp; i ++) {
			seg* sold = sr[rp[i]];
			sr[rp[i]] = sgt. chg(sr[rp[i]], vo, -1);
			sold-> c --;
			sgt. recycle(sold);
		}
	}
	void insert(int p0, int v0) {
		int pi = ++ tn;
		ls[pi] = 0;
		rs[pi] = 0;
		sz[pi] = 1;
		vl[pi] = v0;
		sr[pi] = sgt. chg(0, v0, 1);
		int p = rt, rp[maxl], trp = 0;
		if (p0 == sz[p] + 1) {
			while (p) {
				rp[++ trp] = p;
				sz[p] ++;
				seg* sold = sr[p];
				sr[p] = sgt. chg(sr[p], v0, 1);
				sold-> c --;
				sgt. recycle(sold);
				if (rs[p])
					p = rs[p];
				else
					break;
			}
			rs[p] = pi;
		}
		else {
			while (p) {
				rp[++ trp] = p;
				sz[p] ++;
				seg* sold = sr[p];
				sr[p] = sgt. chg(sr[p], v0, 1);
				sold-> c --;
				sgt. recycle(sold);
				if (sz[ls[p]] + 1 == p0)
					break;
				else if (sz[ls[p]] >= p0)
					p = ls[p];
				else
					p0 -= sz[ls[p]] + 1, p = rs[p];
			}
			if (!ls[p])
				ls[p] = pi;
				else {
					p = ls[p];
					while (p) {
						rp[++ trp] = p;
						sz[p] ++;
						seg* sold = sr[p];
						sr[p] = sgt. chg(sr[p], v0, 1);
						sold-> c --;
						sgt. recycle(sold);
						if (!rs[p])
							break;
						else
							p = rs[p];
					}
					rs[p] = pi;
				}
			}
			int pc = -1;
			double mc = 0;
			for (int i = trp; i; i --)
				if (balanceVal(rp[i]) > mc)
					mc = balanceVal(rp[i]), pc = i;
			if (mc > balanceConst) {
				int rn = rebuild(rp[pc]);
				if (pc > 1) {
					if (rp[pc] == ls[rp[pc - 1]])
						ls[rp[pc - 1]] = rn;
					else
						rs[rp[pc - 1]] = rn;
				}
				else
					rt = rn;
			}
		}
		void getChain(seg** a, int& t, int k) {
			int p = rt;
			t = 0;
			while (p && k)
				if (sz[ls[p]] == k) {
					a[t ++] = sr[ls[p]];
					if (sr[ls[p]])
						sr[ls[p]]-> c ++;
					break;
				}
				else if (sz[ls[p]] < k) {
					a[t] = sgt. chg(sr[ls[p]], vl[p], 1);
					a[t ++]-> c = 0;
					k -= sz[ls[p]] + 1;
					p = rs[p];
				}
				else
					p = ls[p];
		}
		int query(int l0, int r0, int k) {
			seg *cl[maxl], *cr[maxl], *rold[maxl * 2];
			int tl, tr;
			getChain(cl, tl, l0 - 1);
			getChain(cr, tr, r0);
			for (int i = 0; i < tl; i ++)
				rold[i] = cl[i];
			for (int i = 0; i < tr; i ++)
				rold[tl + i] = cr[i];
			int l = 0, r = maxn;
			while (l < r) {
				int s = 0;
				for (int i = 0; i < tl; i ++)
					s -= von(lson(cl[i]));
				for (int i = 0; i < tr; i ++)
					s += von(lson(cr[i]));
				if (s >= k) {
					r = (l + r) >> 1;
					for (int i = 0; i < tl; i ++)
						cl[i] = lson(cl[i]);
					for (int i = 0; i < tr; i ++)
						cr[i] = lson(cr[i]);
				}
				else {
					k -= s;
					l = ((l + r) >> 1) + 1;
					for (int i = 0; i < tl; i ++)
						cl[i] = rson(cl[i]);
					for (int i = 0; i < tr; i ++)
						cr[i] = rson(cr[i]);
				}
			}
			for (int i = 0; i < tl + tr; i ++)
				if (rold[i])
					sgt. recycle(rold[i]);
			return l;
		}
		void debOut(int p = -1) {
			if (p == -1)
				p = rt;
			if (!p)
				return;
			debOut(ls[p]);
			printf("%4d", vl[p]);
			debOut(rs[p]);
			if (p == rt)
				printf("	length = %d\n", sz[p]);
		}
};

scapegoattree sct;

int n, m, lans;

int main() {
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin);
#endif

	sgt. init();
	sct. init();
	n = nextInt();
	for (int i = 1; i <= n; i ++)
		sct. addBuf(nextInt());
	sct. build();
	m = nextInt();
	lans = 0;
	while (m --) {
		char opt;
		int x, y, z;
		scanf("\n%c", &opt);
		if (opt == 'Q') {
			x = nextInt() ^ lans;
			y = nextInt() ^ lans;
			z = nextInt() ^ lans;
			printf("%d\n", (lans = sct. query(x, y, z)));
		}
		else if (opt == 'M') {
			x = nextInt() ^ lans;
			y = nextInt() ^ lans;
			sct. change(x, y);
		}
		else if (opt == 'I') {
			x = nextInt() ^ lans;
			y = nextInt() ^ lans;
			sct. insert(x, y);
		}
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值