bzoj1901zoj2112

bzoj1901听说不用建静态主席树,可以直接当树状数组添加也不会爆内存,然而并没有权限号。由于zoj2112的n有5*1e5所以不能一开始就nlognlogn的空间丢进去,不然会炸,需要建一颗nlogn空间的静态线段树,然后再mlognlogn的跟新,这样就不会爆数组。静态开一个rt1[maxl],动态开一个rt2[maxl]

因为是要动态修改的区间第k大,把主席树当树状数组来看待,要求l到r的第k大就是,求用前r减去前l-1,然后用树状数组的方式,来更新和统计。在统计前i个的左子树的总和的时候,要把动态的树状数组主席树的值加起来,然后再加上静态的主席树的值,才能得到权值为l到r的左子树的总和值。

#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxl 50010
#define inf 2000000001

using namespace std;

int n,m,cnt,tot,sz;
int a[maxl],dy[maxl<<1],rt1[maxl],rt2[maxl],inl[maxl],inr[maxl];
struct node
{
	int ls,rs,sum;
}tree[maxl*50];
struct num
{
	int num,ind;
	bool isa;		
}aa[maxl<<1];
struct que
{
	int l,r,k;
	bool flag;
}q[maxl/5];
char ch[2];

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

bool cmp(const num &x,const num &y)
{
	return x.num<y.num;
}

void prework()
{
	memset(tree,0,sizeof(tree));
	memset(rt1,0,sizeof(rt1));
	memset(rt2,0,sizeof(rt2)); 
	sz=0;
	n=read();m=read();
	for(int i=1;i<=n;i++)
		a[i]=read(),aa[i].num=a[i],aa[i].ind=i,aa[i].isa=true;
	tot=n;
	for(int i=1;i<=m;i++)
	{
		scanf("%s",ch);
		if(ch[0]=='Q')
		{
			q[i].l=read();q[i].r=read();q[i].k=read();
			q[i].flag=false;
		}
		else
		{
			q[i].l=read();q[i].k=read();
			q[i].flag=true;
			aa[++tot].num=q[i].k;aa[tot].ind=i;aa[tot].isa=false;
		}
	}
	sort(aa+1,aa+1+tot,cmp);
	cnt=0;aa[0].num=-inf;
	for(int i=1;i<=tot;i++)
	{
		if(aa[i].num!=aa[i-1].num)
			cnt++,dy[cnt]=aa[i].num;
		if(aa[i].isa)
			a[aa[i].ind]=cnt;
		else
			q[aa[i].ind].k=cnt;
	}
}

void update(int last,int l,int r,int &root,int w,int x)
{
	root=++sz;
	tree[sz]=tree[last];
	tree[sz].sum+=x;
	if(l==r)
		return;
	int mid=(l+r)>>1;
	if(w<=mid)
		update(tree[last].ls,l,mid,tree[sz].ls,w,x);
	else
		update(tree[last].rs,mid+1,r,tree[sz].rs,w,x);	
}

int query(int l,int r,int k,int s1,int s2)
{
	if(l==r) return l;
	int i,suml=0,sumr=0;
	for(int i=1;i<=inl[0];i++) suml+=tree[tree[inl[i]].ls].sum;
	for(int i=1;i<=inr[0];i++) sumr+=tree[tree[inr[i]].ls].sum;
	suml+=tree[tree[s1].ls].sum;sumr+=tree[tree[s2].ls].sum;
	int mid=(l+r)>>1,tmp=sumr-suml;
	if(tmp>=k)
	{
		for(int i=1;i<=inl[0];i++) inl[i]=tree[inl[i]].ls;
		for(int i=1;i<=inr[0];i++) inr[i]=tree[inr[i]].ls;
		return query(l,mid,k,tree[s1].ls,tree[s2].ls);
	}
	else
	{
		for(int i=1;i<=inl[0];i++) inl[i]=tree[inl[i]].rs;
		for(int i=1;i<=inr[0];i++) inr[i]=tree[inr[i]].rs;
		return query(mid+1,r,k-tmp,tree[s1].rs,tree[s2].rs);
	}
}

void mainwork()
{
	for(int i=1;i<=n;i++)
		update(rt1[i-1],1,cnt,rt1[i],a[i],1);
	for(int i=1;i<=m;i++)
	if(!q[i].flag)
	{
		inl[0]=0;inr[0]=0;
		for(int j=q[i].l-1;j;j-=j&-j)
			inl[++inl[0]]=rt2[j];
		for(int j=q[i].r;j;j-=j&-j)
			inr[++inr[0]]=rt2[j];
		printf("%d\n",dy[query(1,cnt,q[i].k,rt1[q[i].l-1],rt1[q[i].r])]);
	}
	else
	{
		for(int j=q[i].l;j<=n;j+=j&-j)
			update(rt2[j],1,cnt,rt2[j],a[q[i].l],-1);
		a[q[i].l]=q[i].k;
		for(int j=q[i].l;j<=n;j+=j&-j) 
			update(rt2[j],1,cnt,rt2[j],a[q[i].l],1);
	}
}

int main()
{
	int t=read();
	for(int i=1;i<=t;i++)
	{
		prework();
		mainwork();
	}
	return 0;
}


发布了496 篇原创文章 · 获赞 37 · 访问量 8万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览