BZOJ 1901: Zju2112 Dynamic Rankings 树状数组套主席树

1901: Zju2112 Dynamic Rankings

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 8046  Solved: 3356
[Submit][Status][Discuss]

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继续回答上面的问题。

Input

第一行一个数字N,代表测试组数
对于每组数据第一行有两个正整数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

Output

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

Sample Input

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

Sample Output

3
6

HINT

m,n≤10000。


题面有问题!!!根本没有什么多组数据

树状数组套主席树,O(nlog^2n)


#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<complex>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<map>
#include<set>
using namespace std;

typedef long long ll;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
	return x*f;
}
inline void print(int x)
{if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar('0'+x%10);}

const int N=100100;

int h[N<<1],num[N<<1],root[N];

inline int hsh(int x,int n)
{
	register int l=1,r=n,mid;
	while(l<r){mid=(l+r)>>1;h[mid]<x?l=mid+1:r=mid;}
	return l;
}

int cnt;

struct president_tree{int sum,ls,rs;}tr[N<<5];

void insert(int &k,int x,int l,int r,int aim,int val)
{
     k=++cnt;
     tr[k].sum=tr[x].sum+val;tr[k].rs=tr[x].rs;tr[k].ls=tr[x].ls;
     if(l==r)return;
     int mid=(l+r)>>1;
     if(aim<=mid)insert(tr[k].ls,tr[x].ls,l,mid,aim,val);
     else insert(tr[k].rs,tr[x].rs,mid+1,r,aim,val);
}

int ltr[N],rtr[N],tot;

inline void query(int x,int y,int rk)
{
	register int l=1,r=tot,i,mid,sum;
	for(i=y;i;i-=(i&-i))rtr[i]=root[i];
	for(i=x;i;i-=(i&-i))ltr[i]=root[i];
	while(l<r)
	{
		sum=0;
		for(i=y;i;i-=(i&-i))sum+=tr[tr[rtr[i]].ls].sum;
		for(i=x;i;i-=(i&-i))sum-=tr[tr[ltr[i]].ls].sum;
		mid=l+r>>1;
		if(rk<=sum)
		{
			for(i=y;i;i-=(i&-i))rtr[i]=tr[rtr[i]].ls;
			for(i=x;i;i-=(i&-i))ltr[i]=tr[ltr[i]].ls;
			r=mid;
		}
		else
		{
			for(i=y;i;i-=(i&-i))rtr[i]=tr[rtr[i]].rs;
			for(i=x;i;i-=(i&-i))ltr[i]=tr[ltr[i]].rs;
			rk-=sum;l=mid+1;
		}
	}
	print(h[l]);puts("");
}

bool eq[N];

int L[N],R[N],K[N],a[N];

int main()
{
	register int i,j,n,m,tmp;
	register char opt;
	n=read();m=read();tot=n;tmp=1;
	for(i=1;i<=n;++i)a[i]=read(),num[i]=a[i];
	for(i=1;i<=m;++i)
	{
		opt=' ';
		while(opt^'Q'&&opt^'C')opt=getchar();L[i]=read();R[i]=read();
		opt=='Q'?(eq[i]=1,K[i]=read()):(eq[i]=0,num[++tot]=R[i]);
	}
	sort(num+1,num+1+tot);h[1]=num[1];
	for(i=2;i<=tot;++i)if(num[i]!=num[i-1])h[++tmp]=num[i];
	tot=tmp;
	for(i=1;i<=n;++i)
	{
		tmp=hsh(a[i],tot);
		for(j=i;j<=tot;j+=(j&-j))
		insert(root[j],root[j],1,tot,tmp,1);
	}
	for(i=1;i<=m;++i)
	{
		if(eq[i])query(L[i]-1,R[i],K[i]);
		else 
		{
			tmp=hsh(a[L[i]],tot);//¡£¡£¡£mistook a[i] for a[L[i]]    bi¡ª¡ª 
			for(j=L[i];j<=n;j+=(j&-j))insert(root[j],root[j],1,tot,tmp,-1);
			tmp=hsh(R[i],tot);
			for(j=L[i];j<=n;j+=(j&-j))insert(root[j],root[j],1,tot,tmp,1);
			a[L[i]]=R[i];
		}
	}
}

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

3
6
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值