大视野1901: Zju2112 (树状数组+主席树)

Description

给定一个含有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。

Input

对于每一次询问,你都需要输出他的答案,每一个输出占单独的一行。

Output

Sample Input

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

Sample Output

3
6
题意:求区间第K小值,值可变更
思路:不要求修改的区间第K小值问题中,主席树的每棵线段树维护前缀或者后缀的位置的情况。可修改,也就是单点更新的话就不能这样了。因为每次修改的话会导致前缀或者后缀的所有线段树都要更改。具体是主席树的每颗线段树只维护树状数组上一个区间的位置的情况,前缀和的统计用树状数组来实现。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define maxn 20080
#define maxm 5500000
#define lowbit(x) x&(-x)
int T[maxn],Tnow[maxn],key[maxn<<1],X[maxn<<1];
int lson[maxm],rson[maxm],c[maxm];
int tot,n,cnt;
int build(int l,int r)
{
	int root = tot++,tmp = root;
	if(l != r)
	{
		int mid = (l+r) >> 1;
		lson[root] = build(l,mid);
		rson[root] = build(mid+1,r);
	}
	return tmp;
}

int update(int root,int pos,int val)
{
	int newnode = tot++,tmp = newnode;
	int l = 1,r = cnt;
	while(l < r)
	{
		int mid = (l + r) >> 1;
		if(pos <= mid)
		{
			lson[newnode] = tot++,rson[newnode] = rson[root];
			root = lson[root],newnode = lson[newnode];
			r = mid;
		}
		else
		{
			lson[newnode] = lson[root],rson[newnode] = tot++;
			root = rson[root],newnode = rson[newnode];
			l = mid+1;
		}
		c[newnode] = c[root] + val;
	}
	return tmp;
}

void query_init(int x)
{
	while(x > 0)
	{
		Tnow[x] = T[x];
		x -= lowbit(x);
	}
}

int sum(int x)
{
	int ret = 0;
	while(x > 0)
	{
		ret += c[lson[Tnow[x]]];
		x -= lowbit(x);
	}
	return ret;
}

int Query(int L,int R,int k)
{
	query_init(L-1),query_init(R);
	int l = 1,r = cnt;
	while(l < r)
	{
		int mid = (l+r) >> 1;
		int temp = sum(R) - sum(L-1);
		if(temp >= k)
		{
			int x = L-1,y = R;
			while(x > 0)
			{
				Tnow[x] = lson[Tnow[x]];
				x -= lowbit(x);
			}
			while(y > 0)
			{
				Tnow[y] = lson[Tnow[y]];
				y -= lowbit(y);
			}
			r = mid;
		}
		else 
		{
			k -= temp;
			int x = L-1,y = R;
			while(x > 0)
			{
				Tnow[x] = rson[Tnow[x]];
				x -= lowbit(x);
			}
			while(y > 0)
			{
				Tnow[y] = rson[Tnow[y]];
				y -= lowbit(y);
			}
			l = mid+1;
		}
	}
	return l;
}

struct Que
{
	char ope;
	int u,v,k;
	Que(){}
	Que(char c,int uu,int kk)
	{
		ope = c,u = uu,k = kk;
	}
	Que(char c,int uu,int vv,int kk)
	{
		ope = c,u = uu,v = vv,k = kk;
	}
}que[maxn];
int main()
{
	//freopen("in.txt","r",stdin);
	int n,m;
	while(scanf("%d%d",&n,&m)==2)
	{
		for(int i = 1;i <= n;i++)
			scanf("%d",&key[i]);
		cnt = n;
		for(int i = 1;i <= m;i++)
		{
			char ope[2];
			int u,v,k;
			scanf("%s",ope);
			if(ope[0] == 'Q')
			{
				scanf("%d%d%d",&u,&v,&k);
				que[i] = Que(ope[0],u,v,k);
			}
			else 
			{
				scanf("%d%d",&u,&k);
				que[i] = Que(ope[0],u,k);
				key[++cnt] = k;
			}
		}
		memcpy(X,key,sizeof(key));
		sort(X+1,X+1+cnt);
		T[0] = build(1,cnt);
		for(int i = 1;i <= n;i++)	T[i] = T[0];
		for(int i = 1;i <= n;i++)	
		{
			int x = lower_bound(X+1,X+1+cnt,key[i]) - X;
			for(int j = i;j <= cnt;j += lowbit(j))
			{
				T[j] = update(T[j],x,1);
			}
		}
		for(int i = 1;i <= m;i++)
		{
			if(que[i].ope == 'C')
			{
				int x = que[i].u;
				int y = lower_bound(X+1,X+1+cnt,key[x]) - X;
				while(x <= cnt)
				{
					T[x] = update(T[x],y,-1);
					x += lowbit(x);
				}
				x = que[i].u,y = lower_bound(X+1,X+1+cnt,que[i].k) - X;
				key[x] = que[i].k;
				while(x <= cnt)
				{
					T[x] = update(T[x],y,1);
					x += lowbit(x);
				}
			}
			else 
			{
				printf("%d\n",X[Query(que[i].u,que[i].v,que[i].k)]);
			}
		}
	}
	return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值