和Leo一起做热爱线段树的好孩子「LibreOJ β Round #2」计算几何瞎暴力

YMH在一个月之前写了这个题

当时我不知所云

现在看来数据结构水平还是在提升的。QwQ

最先想的线段树二进制拆分

但是似乎不行,因为排序不行

这个时候可持久化字典树横空出世:他里面的数本身有序

有可以支持异或(交换左右儿子就好了)

然后对于还没有排序的

维护二进制前缀和,暴力算是log的

然后就完了

#include<bits/stdc++.h>
using namespace std;
typedef int INT;
#define int long long 
inline void read(int &x){
    x=0;
    char ch=getchar();
    int f=1;
    while(ch<'0'||ch>'9'){
        if(ch=='-')f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=x*10+ch-'0';
        ch=getchar();
    }
    x*=f;
}
int del;
const int N=2e5+100;
struct Trie{
	int ch[N*31][2];
	int sum[N*31][31];
	int siz[N*31];
	int Lazy;
	int rt;
	int cnt;
	Trie(){
		rt=1;
		cnt=1;
	}
	int Get_siz(){
		return siz[ch[rt][0]]+siz[ch[rt][1]];
	}
	int Get_Num(int Id){
		int ret=0;
		for(int i=0;i<=30;i++){
			if(del&(1<<i)){
				ret+=(1<<i)*(siz[Id]-sum[Id][i]);
			}
			else ret+=(1<<i)*sum[Id][i];
		}
		return ret; 
	}
	void Insert(int x){
		int now=rt;
		for(int i=30;i>=0;i--){
			int Id=((x>>i)&1);
			if(!ch[now][Id]){
				ch[now][Id]=++cnt;
			}
			now=ch[now][Id];
			for(int j=30;j>=0;j--){
				if(x&(1<<j)){
					sum[now][j]++;
				}
			}
			siz[now]++;
		}
	}
	int Query(int k){
		if(!k)return 0;
		int now=rt;
		int ans=0;
		for(int i=30;i>=0;i--){
			int l=0;
			int r=1;
			if(Lazy&(1<<i)){
				swap(l,r);
			}				
			if(siz[ch[now][l]]<k){
				k-=siz[ch[now][l]];
				ans+=Get_Num(ch[now][l]);
				now=ch[now][r];
			}
			else now=ch[now][l];
		}
		ans+=Get_Num(now)/siz[now]*k;
		return ans;
	}
}T;
struct presum{
	int len;
	int sum[N][31];
	int a[N];
	void Insert(int x){
		len++;
		a[len]=x;
		for(int i=30;i>=0;i--){
			int now=((x>>i)&1);
			sum[len][i]=sum[len-1][i]+now;
		}
	}
	int Query(int x){
		int ans=0;
		for(int i=0;i<=30;i++){
			if((del>>i)&1)
				ans+=(1<<i)*(x-sum[x][i]);
			else ans+=(1<<i)*sum[x][i];
		}
		return ans;
	}
	void Change(){
		for(int i=1;i<=len;i++){
			T.Insert(a[i]);
		}
		T.Lazy=del;
		len=0;
	}
}Arr;
int n,m;
int A[N];
int Query_Sum(int x){
	if(x<=T.Get_siz()){
		return T.Query(x);
	}
	else{
		return T.Query(T.Get_siz())+Arr.Query(x-T.Get_siz());
	}
}
INT main(){
//	freopen("test.in","r",stdin);
	read(n);
	for(int i=1;i<=n;i++){
		read(A[i]);
	}
	for(int i=1;i<=n;i++){
		Arr.Insert(A[i]);
	}
	read(m);
	for(int i=1;i<=m;i++){
		int opt;
		read(opt);
		if(opt==1){
			n++;
			read(A[n]);
			A[n]^=del;
			Arr.Insert(A[n]);
		}
		if(opt==2){
			int l,r;
			read(l);
			read(r);
			cout<<Query_Sum(r)-Query_Sum(l-1)<<'\n';
		}
		if(opt==3){
			int x;
			read(x);
			del^=x;
		}
		if(opt==4){
			Arr.Change();
		}
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值