LOJ517 计算几何瞎暴力

题目传送门

分析:
没有操作4怎么做?
暴力维护数组,加入就暴力加入,对于这些数维护二进制下每一位1的个数的前缀和,全局异或打一个标记,查询的时候按位前缀和作差就好了
现在有了操作4怎么做?
发现如果一个前缀已经排好了序,这个前缀内部的顺序就不再会被打乱了,考虑使用Trie维护这个前缀
对Trie也打一个异或标记,求前缀和在Trie上向下找的时候考虑一下这个异或标记再决定向左向右
同样也可以在每个节点维护经过这个节点的路径代表的数二进制下每一位1的个数的和,查询时直接返回所有做贡献节点的和就好了
注意到最底端可能出现多个数字在一个节点的情况,注意特判
现在我们Trie和数组结合使用
每次加入数时暴力加入数组,要排序时再把数组里面的数加入Trie中,数组清空
每个数进一次数组且最多出一次数组,复杂度\(O(nlog^2A)\)
平方是因为我每个节点都维护了每一位的和,不清楚怎么优雅\(O(nlogA)\)
有会的大佬可以评论D我QwQ,扑通扑通跪下来

#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<algorithm>
#include<queue>
#include<bitset>
#include<map>
#include<set>

#define maxn 100005
#define INF 0x3f3f3f3f

using namespace std;

inline int getint()
{
	int num=0,flag=1;char c;
	while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;
	while(c>='0'&&c<='9')num=num*10+c-48,c=getchar();
	return num*flag;
}

int n,m;
int a[maxn],sum[maxn][30],N;
int ch[maxn<<5][2],sz[maxn<<5],Sum[maxn<<5][30];
int rt,tot,tag,Sz,Tag;

inline void Insert(int x)
{
	int u=rt;Sz++;
	for(int i=29;~i;i--)
	{
		int id=((x&(1<<i))>0);
		if(!ch[u][id])ch[u][id]=++tot;
		u=ch[u][id],++sz[u];
		for(int j=0;j<30;j++)if(x&(1<<j))Sum[u][j]++;
	}
}
inline long long getsum(int x)
{
	long long ans=0;
	for(int i=0;i<30;i++)
		if(Tag&(1<<i))ans+=(1ll*sz[x]-Sum[x][i])<<i;
		else ans+=(1ll*Sum[x][i])<<i;
	return ans;
}
long long Query(int x)
{
	if(x==0)return 0;
	int u=rt;
	long long ans=0;
	for(int i=29;~i;i--)
	{
		int l=0,r=1;
		if(tag&(1<<i))swap(l,r);
		if(x<=sz[ch[u][l]])u=ch[u][l];
		else ans+=getsum(ch[u][l]),x-=sz[ch[u][l]],u=ch[u][r];
	}
	ans+=getsum(u)/sz[u]*x;
	return ans;
}

inline void insert(int x)
{
	x^=Tag,a[++N]=x;
	for(int i=0;i<30;i++)sum[N][i]=sum[N-1][i]+((x&(1<<i))>0);
}
inline long long query(int x)
{
	long long ans=0;
	for(int i=0;i<30;i++)
		if(Tag&(1<<i))ans+=(1ll*x-sum[x][i])<<i;
		else ans+=(1ll*sum[x][i])<<i;
	return ans;
}
inline long long getans(int x)
{
	if(x<=Sz)return Query(x);
	return Query(Sz)+query(x-Sz);
}

int main()
{
	n=getint();
	for(int i=1;i<=n;i++)insert(getint());
	m=getint();
	for(int i=1;i<=m;i++)
	{
		int op=getint();
		if(op==1)insert(getint());
		if(op==2)
		{
			int l=getint()-1,r=getint();
			printf("%lld\n",getans(r)-getans(l));
		}
		if(op==3)Tag^=getint();
		if(op==4){tag=Tag;for(int i=1;i<=N;++i)Insert(a[i]);N=0;}
	}
}

posted @ 2020-07-07 16:20  Izayoi_Doyo  阅读(179)  评论(0编辑  收藏  举报