【bzoj1901】Zju2112 Dynamic Rankings

题目描述:

给定一个含有n个数的序列a[1],a[2],a[3]……a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]……a[j]中第k小的数是多少(1≤k≤j-i+1),并且,你可以改变一些a[i]的值,改变后,程序还能针对改变后的a继续回答上面的问题。你需要编一个这样的程序,从输入文件中读入序列a,然后读入一系列的指令,包括询问指令和修改指令。对于每一个询问指令,你必须输出正确的回答。 第一行有两个正整数n(1≤n≤10000),m(1≤m≤10000)。分别表示序列的长度和指令的个数。第二行有n个数,表示a[1],a[2]……a[n],这些数都小于10^9。接下来的m行描述每条指令,每行的格式是下面两种格式中的一种。 Q i j k 或者 C i t Q i j k (i,j,k是数字,1≤i≤j≤n, 1≤k≤j-i+1)表示询问指令,询问a[i],a[i+1]……a[j]中第k小的数。C i t (1≤i≤n,0≤t≤10^9)表示把a[i]改变成为t。

样例输入:

5 3
3 2 1 4 7
Q 1 4 3
C 2 6
Q 2 5 3


样例输出:

3
6


题解:
序列上的带修改的求区间第k小。树状数组套可持久化线段树。其实主席树的每一次Insert相当于一次线性变化(大雾),然后普通的主席树是按照上一个版本进行的变化,如果要修改的话那就用树状数组来维护这个线性变化,使得修改的复杂度从O(nlogn)降到了O((logn)^2)。


代码:

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

#ifdef WIN32
	#define LL "%I64d"
#else
	#define LL "%lld"
#endif

#ifdef CT
	#define debug(...) printf(__VA_ARGS__)
	#define setfile() 
#else
	#define debug(...)
	#define filename ""
	#define setfile() freopen(filename".in","r",stdin);freopen(filename".out","w",stdout);
#endif

#define R register
#define getc() (S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T)?EOF:*S++)
#define dmax(_a, _b) ((_a) > (_b) ? (_a) : (_b))
#define dmin(_a, _b) ((_a) < (_b) ? (_a) : (_b))
#define cmax(_a, _b) (_a < (_b) ? _a = (_b) : 0)
#define cmin(_a, _b) (_a > (_b) ? _a = (_b) : 0)
char B[1<<15],*S=B,*T=B;
inline int FastIn()
{
	R char ch;R int cnt=0;R bool minus=0;
	while (ch=getc(),(ch < '0' || ch > '9') && ch != '-');
	ch == '-' ?minus=1:cnt=ch-'0';
	while (ch=getc(),ch >= '0' && ch <= '9') cnt = cnt * 10 + ch - '0';
	return minus?-cnt:cnt;
}
#define maxt 6200010
#define maxn 10010
const int oo = 1e9;
int root[maxn], sum[maxt], ls[maxt], rs[maxt], tot, lcnt, rcnt, val[maxn], lr[maxn], rr[maxn];
#define lowbit(_x) ((_x) & -(_x))
int update (R int last, R int l, R int r, R int pre,R int c)
{
	R int mid = l + r >> 1, nw = ++tot;
	sum[nw] = sum[last] + c;
	if (l == r) return nw;
	if (pre > mid)
	{
		ls[nw] = ls[last];
		rs[nw] = update(rs[last], mid + 1, r, pre, c);
	}
	else
	{
		rs[nw] = rs[last];
		ls[nw] = update(ls[last], l, mid, pre, c);
	}
	return nw;
}
inline int query(R int l, R int r, R int k)
{
	while (l < r)
	{
		R int lsum = 0, rsum = 0, mid = l + r >> 1;
		for (R int i = 1; i <= lcnt; ++i)
			lsum += sum[ls[lr[i]]];
		for (R int i = 1; i <= rcnt; ++i)
			rsum += sum[ls[rr[i]]];
		if (rsum - lsum >= k)
		{
			for (R int i = 1; i <= lcnt; ++i)
				lr[i] = ls[lr[i]];
			for (R int i = 1; i <= rcnt; ++i)
				rr[i] = ls[rr[i]];
			r = mid;
		}
		else
		{
			for (R int i = 1; i <= lcnt; ++i)
				lr[i] = rs[lr[i]];
			for (R int i = 1; i <= rcnt; ++i)
				rr[i] = rs[rr[i]];
			l = mid + 1;
			k -= (rsum - lsum);
		}
	}
	return l;
}
int main()
{
//	setfile();
	R int n = FastIn(), q = FastIn();
	for (R int i = 1; i <= n; ++i)
	{
		R int a = FastIn();
		for (R int j = i; j <= n; j += lowbit(j))
			root[j] = update(root[j], 0, oo, a, 1);
		val[i] = a;
	}
	for (R int i = 1; i <= q; ++i)
	{
		R char cmd = getc();
		while (cmd!='Q'&&cmd!='C') cmd = getc();
		R int a = FastIn(), b = FastIn();
		if (cmd == 'Q')
		{
			R int k = FastIn();
			lcnt  = rcnt = 0;
			for (R int j = a - 1; j; j -= lowbit(j))
				lr[++lcnt] = root[j];
			for (R int j = b; j; j -= lowbit(j))
				rr[++rcnt] = root[j];
			printf("%d\n",query(0, oo, k) );
		}
		else
		{
			for (R int j = a; j <= n; j += lowbit(j))
				root[j] = update(root[j], 0, oo, val[a], -1);
			val[a] = b;
			for (R int j = a; j <= n; j += lowbit(j))
				root[j] = update(root[j], 0, oo, b, 1);
		}
	}
	return 0;
}



 

posted @ 2016-03-16 16:57  cot  阅读(...)  评论(...编辑  收藏