ZJU2112 Dynamic Rankings 树状数组套主席树

很简单嗯,我们离散后直接上主席树维护前缀和就行,嗯很简单,然后惊人的MLE了= =

然后找了一个别人过的程序写了一个对拍,然后睡午觉去了

起来了发现并没有挂掉,只是一交就MLE 

那么我们有没有什么优化的方法呢?

显然是有的,观察下题目,发现题目中M的范围小于N,而且小了很多!这明显不正常,正常来说操作的个数应该是和N是同阶的,甚至更大才对

再观察下内存使用,发现都是最开始那些初始值占的内存超多

显然我们也并没有必要把这些东西插入到树状数组里

单独把初值建成一坨主席树然后就可以了对吧

查询的时候分开查询下就行啦

空间一下子就从nlognlogn变成了mlognlogn+nlogn,稍微卡卡空间就过了

AC时空间是31916,题库给的是32M= =

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<ctime>
#define LL long long
#define DB double 
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define efo(i,x) for(int i=last[x];i!=0;i=e[i].next)
using namespace std;
inline LL read()
{
	LL d=0,f=1;char s=getchar();
	while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
	while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
	return d*f;
}
#define N 50005
#define M 10005
#define B 50
struct question{
	int l,r,k,id;
	char flag;
}Q[M*2];
int a[N*2],hash[N*2],nm;
int root[N*2],sz;
int sum[N*B],ls[N*B],rs[N*B];
int L[N],R[N];
int num[N*2],tot;
int n,m;

int lowbit(int x){
	return x&(-x);
}

int find(int x){
	int l=1,r=nm,ret;
	while(l<=r){
		int ret=(l+r)>>1;
		if(hash[ret]==x)return ret;
		if(hash[ret]<x)l=ret+1;
		else r=ret-1;
	}
}

void updata(int last,int l,int r,int &rt,int val,int ch){
	rt=++sz;
	sum[rt]=sum[last]+ch;
	ls[rt]=ls[last];rs[rt]=rs[last];
	if(l==r)return;
	int mid=(l+r)>>1;
	if(val<=mid)updata(ls[last],l,mid,ls[rt],val,ch);
	else updata(rs[last],mid+1,r,rs[rt],val,ch);
}

int Query(int k,int l,int r,int ll,int rr){
	if(l==r)return l;
	int suml=0,sumr=0;
	fo(i,1,ll)suml+=sum[ls[L[i]]];
	fo(i,1,rr)sumr+=sum[ls[R[i]]];
	int mid=(l+r)>>1;
	if(sumr-suml>=k){
		fo(i,1,ll)L[i]=ls[L[i]];
		fo(i,1,rr)R[i]=ls[R[i]];
		return Query(k,l,mid,ll,rr);
	}else{
		fo(i,1,ll)L[i]=rs[L[i]];
		fo(i,1,rr)R[i]=rs[R[i]];
		return Query(k-(sumr-suml),mid+1,r,ll,rr);
	}
}

void init_clr(){
	memset(Q,0,sizeof(Q));
	memset(a,0,sizeof(a));
	memset(num,0,sizeof(num));
	memset(sum,0,sizeof(sum));
	memset(ls,0,sizeof(ls));
	memset(rs,0,sizeof(rs));
	memset(root,0,sizeof(root));
	memset(hash,0,sizeof(hash));
	tot=0;nm=0;sz=0;n=m=0;
}

char getNxt(){
	char s=getchar();
	while(s!='Q'&&s!='C')s=getchar();
	return s;
}

void init_read(){
	n=read(),m=read();
	fo(i,1,n)a[i]=read(),num[++tot]=a[i];
	fo(i,1,m){
		char ch=getNxt();
		if(ch=='Q'){
			Q[i].flag=ch;
			Q[i].l=read(),Q[i].r=read();
			Q[i].k=read();
		}else{
			Q[i].flag=ch;
			Q[i].l=read();
			Q[i].k=read();
			num[++tot]=Q[i].k;
		}
	}
}

void LS(){
	sort(num+1,num+tot+1);
	hash[++nm]=num[1];
	fo(i,2,tot){
		if(num[i]!=num[i-1]){
			hash[++nm]=num[i];
		}
	}
}

void build(int &k,int l,int r,int val){
	sum[++sz]=sum[k]+1;
	ls[sz]=ls[k];rs[sz]=rs[k];
	k=sz;
	
	if(l==r)return;
	int mid=(l+r)>>1;
	if(val<=mid)build(ls[k],l,mid,val);
	else build(rs[k],mid+1,r,val);
}

void buildtree(){
	fo(i,1,n){
		root[i+n]=root[i+n-1];
		int x=find(a[i]);
		build(root[i+n],1,nm,x);
	}
}

void work(){
	fo(i,1,m){
//		cerr<<i<<' '<<m<<' '<<(char)Q[i].flag<<' '<<Q[i].l<<' '<<Q[i].r<<' '<<Q[i].k<<endl;
		if(Q[i].flag!='Q'&&Q[i].flag!='C'){
			cerr<<i<<endl;
			return;
		}
		if(Q[i].flag=='Q'){
			Q[i].l--;
			int a=0,b=0;
			L[++a]=root[Q[i].l?Q[i].l+n:0];
			R[++b]=root[Q[i].r+n];
			for(int j=Q[i].l;j>0;j-=lowbit(j)){
				L[++a]=root[j];
			}
			for(int j=Q[i].r;j>0;j-=lowbit(j)){
				R[++b]=root[j];
			}
			int temp=Query(Q[i].k,1,nm,a,b);
			int ans=hash[temp];
			printf("%d\n",ans);
		}else{
			int val=find(a[Q[i].l]);
			for(int j=Q[i].l;j<=n;j+=lowbit(j)){
				updata(root[j],1,nm,root[j],val,-1);
			}
			a[Q[i].l]=Q[i].k;
			val=find(Q[i].k);
			for(int j=Q[i].l;j<=n;j+=lowbit(j)){
				updata(root[j],1,nm,root[j],val,1);
			}
		}
	}
}

int main(){
//	freopen("data.in","r",stdin);
//	freopen("data.out","w",stdout);
	int T=read();
	while(T--){
		init_clr();
		init_read();
//		cout<<"finishread"<<endl;
		LS();
//		cout<<"finishLS"<<endl;
		buildtree();
//		cout<<"finishbuild"<<endl;
		work();
//		cout<<"finishwork"<<endl;
	}
	return 0;
}

卡了半天常数和空间的最终版,狗带了120ms还是不在第一版

#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
#define DB double 
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define efo(i,x) for(int i=last[x];i!=0;i=e[i].next)
using namespace std;
inline LL read()
{
	LL d=0,f=1;char s=getchar();
	while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
	while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
	return d*f;
}
#define ENT putchar('\n')
inline void write(LL x)  
{  
    if(x==0){putchar('0');return;}if(x<0)putchar('-'),x=-x;  
    int len=0,buf[20];while(x)buf[len++]=x%10,x/=10;  
    for(int i=len-1;i>=0;i--)putchar(buf[i]+'0');return;  
}  
inline void writeln(LL x){write(x);ENT;}
#define N 50005
#define M 10005
#define B 43
struct question{
	int l,r,k;
	char flag;
}Q[M];
int a[N],hash[N*2],nm;
int root[N*2],sz;
int sum[N*B],ls[N*B],rs[N*B];
int L[30],R[30];
int num[N*2],tot;
int n,m;

inline int lowbit(int x){
	return x&(-x);
}

int l,r,ret;
inline int find(int x){
	l=1,r=nm;
	while(l<=r){
		ret=(l+r)>>1;
		if(hash[ret]==x)return ret;
		if(hash[ret]<x)l=ret+1;
		else r=ret-1;
	}
}

int mid;
void updata(int last,int l,int r,int &rt,int val,int ch){
	rt=++sz;
	sum[rt]=sum[last]+ch;
	ls[rt]=ls[last];rs[rt]=rs[last];
	if(l==r)return;
	mid=(l+r)>>1;
	if(val<=mid)updata(ls[last],l,mid,ls[rt],val,ch);
	else updata(rs[last],mid+1,r,rs[rt],val,ch);
}

int suml,sumr;
int Query(int k,int l,int r,int ll,int rr){
	if(l==r)return l;
	suml=0,sumr=0;
	fo(i,1,ll)suml+=sum[ls[L[i]]];
	fo(i,1,rr)sumr+=sum[ls[R[i]]];
	mid=(l+r)>>1;
	if(sumr-suml>=k){
		fo(i,1,ll)L[i]=ls[L[i]];
		fo(i,1,rr)R[i]=ls[R[i]];
		return Query(k,l,mid,ll,rr);
	}else{
		fo(i,1,ll)L[i]=rs[L[i]];
		fo(i,1,rr)R[i]=rs[R[i]];
		return Query(k-(sumr-suml),mid+1,r,ll,rr);
	}
}

inline void init_clr(){
//	memset(Q,0,sizeof(Q));
//	memset(a,0,sizeof(a));
//	memset(num,0,sizeof(num));
//	memset(sum,0,sizeof(sum));
//	memset(ls,0,sizeof(ls));
//	memset(rs,0,sizeof(rs));
	memset(root,0,sizeof(root));
//	memset(hash,0,sizeof(hash));
	tot=0;nm=0;sz=0;n=m=0;
}

inline char getNxt(){
	char s=getchar();
	while(s!='Q'&&s!='C')s=getchar();
	return s;
}

inline void init_read(){
	n=read(),m=read();
	fo(i,1,n)a[i]=read(),num[++tot]=a[i];
	fo(i,1,m){
		char ch=getNxt();
		if(ch=='Q'){
			Q[i].flag=ch;
			Q[i].l=read(),Q[i].r=read();
			Q[i].k=read();
		}else{
			Q[i].flag=ch;
			Q[i].l=read();
			Q[i].k=read();
			num[++tot]=Q[i].k;
		}
	}
}

inline void LS(){
	sort(num+1,num+tot+1);
	hash[++nm]=num[1];
	fo(i,2,tot){
		if(num[i]!=num[i-1]){
			hash[++nm]=num[i];
		}
	}
}

void build(int &k,int l,int r,int val){
	sum[++sz]=sum[k]+1;
	ls[sz]=ls[k];rs[sz]=rs[k];
	k=sz;
	
	if(l==r)return;
	mid=(l+r)>>1;
	if(val<=mid)build(ls[k],l,mid,val);
	else build(rs[k],mid+1,r,val);
}

inline void buildtree(){
	fo(i,1,n){
		root[i+n]=root[i+n-1];
		int x=find(a[i]);
		build(root[i+n],1,nm,x);
	}
}

int ans,z,b,val;
inline void work(){
	fo(i,1,m){
		if(Q[i].flag=='Q'){
			Q[i].l--;
			z=0,b=0;
			L[++z]=root[Q[i].l?Q[i].l+n:0];
			R[++b]=root[Q[i].r+n];
			for(int j=Q[i].l;j>0;j-=lowbit(j)){
				L[++z]=root[j];
			}
			for(int j=Q[i].r;j>0;j-=lowbit(j)){
				R[++b]=root[j];
			}
			ans=hash[Query(Q[i].k,1,nm,z,b)];
			writeln(ans);
		}else{
			val=find(a[Q[i].l]);
			for(int j=Q[i].l;j<=n;j+=lowbit(j)){
				updata(root[j],1,nm,root[j],val,-1);
			}
			a[Q[i].l]=Q[i].k;
			val=find(Q[i].k);
			for(int j=Q[i].l;j<=n;j+=lowbit(j)){
				updata(root[j],1,nm,root[j],val,1);
			}
		}
	}
}

int main(){
	freopen("data.in","r",stdin);
	freopen("data.out","w",stdout);
	int T=read();
	while(T--){
		init_clr();
		init_read();
//		cout<<"finishread"<<endl;
		LS();
//		cout<<"finishLS"<<endl;
		buildtree();
//		cout<<"finishbuild"<<endl;
		work();
//		cout<<"finishwork"<<endl;
	}
	return 0;
}


你可能感兴趣的:(树状数组,主席树)