bzoj3065

再次写丑的我。。。(刚开始写了个线段树合并+fhq treap完TLE+MLE)

换成替罪羊+可持久化线段树合并之后随机数据1s+,不知道vfk搞得什么新闻,bzoj运行37s+

刚开始题意读错调了1h+我好菜

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define Sum(x) ((x)?(x)->sum:0)
#define Key(x) ((x)?(x)->key:0)
#define Size(x) ((x)?Sum(x->key):0)
#define L(x) ((x)?(x)->l:0)
#define R(x) ((x)?(x)->r:0)
#define maxn 105010
#define fac 0.7
#define MAX 70000
#define N 10000000
using namespace std;
namespace seg{
	struct segment{
		segment *l,*r;
		int sum;
		segment(){l=r=0,sum=0;}
		void update(){sum=Sum(l)+Sum(r);}
		void clear(){l=r=0,sum=0;}
	}pool[N],*pp[N],**pm=pp;
	typedef pair<segment*,segment*> data;
	segment* merge(segment* a,segment* b,int l,int r){
		if(!a&&!b)return 0;
		segment* ptr=*(pm++);ptr->clear();
		if(l==r){
			ptr->sum=Sum(a)+Sum(b);
			return ptr;
		}
		int mid=l+r>>1;
		ptr->l=merge(L(a),L(b),l,mid);
		ptr->r=merge(R(a),R(b),mid+1,r);
		ptr->update();
		return ptr;
	}
	int query(segment* a,int l,int r,int k){
		if(!a||l==r)return 0;
		int mid=l+r>>1;
		if(k<=mid)return query(a->l,l,mid,k);
		else return query(a->r,mid+1,r,k)+Sum(a->l);
	}
	void insert(segment*& a,int l,int r,int k){
		if(!a)a=*(pm++),a->clear();
		a->sum++;
		if(l==r)return ;
		int mid=l+r>>1;
		if(k<=mid)insert(a->l,l,mid,k);
		else insert(a->r,mid+1,r,k);
	}
	void _del(segment*& a,int l,int r,int k){
		a->sum--;
		if(l==r){if(Sum(a)==0)*--pm=a,a=0;return ;}
		int mid=l+r>>1;
		if(k<=mid)_del(a->l,l,mid,k);
		else _del(a->r,mid+1,r,k);
		a->update();
		if(Sum(a)==0)*--pm=a,a=0;
	}
	void del(segment*& a){
		if(!a)return ;
		del(a->l);
		del(a->r);
		*--pm=a;a=0;
	}
	segment* newnode(int k){
		segment* ptr=0;
		insert(ptr,0,MAX,k);
		return ptr;
	}
	void print(segment* a,int l,int r){
	    if(!a)return ;
	    if(l==r){
	        for(int i=1;i<=a->sum;++i)printf("%d ",l);
	        return ;
	    }
	    int mid=l+r>>1;
	    print(a->l,l,mid);
	    print(a->r,mid+1,r);
	}
};
struct gtree{
	gtree *l,*r;
	seg::segment *key;
	int pkey,sum;
	void init(int pkey){
		this->pkey=pkey;
		sum=1,l=r=0;
	}
	void update(){sum=1+Sum(l)+Sum(r);}
}pool[N],*pp[N],**pm=pp,*root,*inv[maxn];
int ptr,a[maxn],b[maxn];
void del(gtree*& g){
	if(!g)return ;
	del(g->l);
	a[++ptr]=g->pkey;
	del(g->r);
	seg::del(g->key);
	*--pm=g;
}
void build(gtree*& g,int l,int r){
	if(l>r)return ;
	int mid=l+r>>1;
	g=*(pm++),g->init(a[mid]);
	build(g->l,l,mid-1);
	build(g->r,mid+1,r);
	g->key=seg::merge(Key(g->l),Key(g->r),0,MAX);
	seg::insert(g->key,0,MAX,g->pkey);
	g->update();
}
void rebuild(gtree*& g){
	ptr=0,del(g),build(g,1,ptr);
}
void insert(gtree*& g,int k,int key){
	if(!g){g=*(pm++),g->init(key);seg::insert(g->key,0,MAX,g->pkey);return ;}
	g->sum++,seg::insert(g->key,0,MAX,key);
//	int a;printf("[%d,%d,%d,%d]",a=rand(),g,g->l,g->r);
//	printf("[%d,%d]",k,key);
	if(Sum(g->l)>=k)insert(g->l,k,key);
	else insert(g->r,k-Sum(g->l)-1,key);
//	printf("[%d,%d]\n",a,g);
	
}
void check(gtree*& g,int k){
	if(!g)return ; 
	if(max(Sum(g->l),Sum(g->r))>Sum(g)*fac)
		{rebuild(g);return ;}
	if(Sum(g->l)>=k)check(g->l,k);
	else check(g->r,k-Sum(g->l)-1);
}
int modify(gtree*& g,int k,int key){
	int a;
	if(k==Sum(g->l)+1){
		seg::_del(g->key,0,MAX,g->pkey);
		seg::insert(g->key,0,MAX,key);
		a=g->pkey,g->pkey=key;
		return a;
	}
	if(Sum(g->l)>=k)a=modify(g->l,k,key);
	else a=modify(g->r,k-Sum(g->l)-1,key);
	seg::_del(g->key,0,MAX,a);
	seg::insert(g->key,0,MAX,key);
	return a;
}
void getinv(gtree*& root,int l,int r){
//	printf("[%d,%d]",l,r);
	if(l>r||!root)return ;
	int lsum=Sum(root->l);
	if(l==1&&Sum(root)==r){inv[++ptr]=root;return ;}
	if(l<=lsum+1&&lsum+1<=r){inv[++ptr]=0,b[ptr]=root->pkey;}
	if(lsum>=r)getinv(root->l,l,r);
	else if(l>lsum+1)getinv(root->r,l-lsum-1,r-lsum-1);
	else getinv(root->l,l,lsum),getinv(root->r,1,r-lsum-1);
}
void dfs(gtree*& root){
	if(!root)return ;
	dfs(root->l);
//	fprintf(stderr,"%d ",root->pkey);
	dfs(root->r);
}
int query(gtree*& root,int l,int r,int k){
	ptr=0,getinv(root,l,r);
	l=0,r=MAX;
	while(l<r){
		int mid=l+r+1>>1;
		int ans=0;
		for(int i=1;i<=ptr;++i){
			if(!inv[i])ans+=mid>b[i];
			else ans+=seg::query(inv[i]->key,0,MAX,mid);
		}
//		printf("[%d,%d,%d]\n",ans,l,r);
		if(ans>=k)r=mid-1;
		else l=mid;
	}
	return l;
}
#define DEBUG
int n,q,lst;
int main(){
	#ifdef DEBUG
	freopen("in.txt","r",stdin);
	freopen("out.txt","w",stdout);
	#endif
//	freopen("err.txt","w",stderr);
	for(int i=0;i<N;++i)seg::pp[i]=seg::pool+i;
	for(int i=0;i<N;++i)pp[i]=pool+i;
	scanf("%d",&n);
	for(int i=1;i<=n;++i)scanf("%d",&a[i]);
	build(root,1,n);
	scanf("%d",&q);
	for(int i=1,x,y,k;i<=q;++i){
		#ifdef DEBUG
		lst=0;
		#endif
//		seg::print(root->key,0,MAX);puts("");
//		dfs(root);fprintf(stderr,"\n");
		char op[2];scanf("%s%d%d",op,&x,&y);
//		fprintf(stderr,"%s %d %d\n",op,x,y);
		x^=lst,y^=lst;
//		printf("[Real:%d,%d]",x,y); 
		if(op[0]=='Q'){
//			if(x==8&&y==8)return 0;
			scanf("%d",&k),k^=lst;
			printf("%d\n",lst=query(root,x,y,k));
		} else if(op[0]=='M'){
			modify(root,x,y);
		} else insert(root,x-1,y),check(root,x-1);
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值