loj517 计算几何瞎暴力

在序列上维护4个操作

1.在序列的尾端添加x

2.输出Al~Ar的和

3.将所有数异或x

4.将序列从小到大排序

第一眼看上去是Splay于是头铁硬刚了一发

后来发现splay没法异或

去百度“维护异或  数据结构”

然后看到了Trie树  学习了一个

1.直接插到序列里

2.考虑前缀和  因为Trie树所管辖的下标区间是有序的,所以这里相当于求Trie树中最小的x个数的,记一下每个点下面数字个数(sz)就可以了

3.考虑整体打一个xortag 对于当前存在的xortag 我们将它的每一位分解到Trie树上跑,如果xortag某一位为1,那么其实相当于该位置的左儿子比右儿子大 处理一下即可

4.把序列插到Trie树里

然后瞎暴力/滑稽

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#define ll long long
#define pi 3.14
#define eps 1e-9
#define INF 2147483233
#define m(a) memset(a,0,sizeof(a))
#define M(a) memset(a,127,sizeof(a))
#define REP(i,m,n) for(int i=1;i<=n;i++)
#define DWN(i,n,m) for(int i=n;i>=1;i++)
#define lowbit(x) x&(-x)
#define POJ(n) while(~scanf("%d",&n) && n)
using namespace std;
const int maxn=1e5,maxh=30;
int xortag,n,m;
struct trie
{
    int ch[maxn*maxh][2];
    int sz[maxn*maxh];
    int sum[maxn*maxh][maxh];
    int root=0;
    int len=0;
    int tag=0;
    void insert(int x)
    {
        int u=root;
        for(int i=maxh-1;i>=0;--i)
        {
            int id=((x&(1<<i))>0);
            if(!ch[u][id]) ch[u][id]=++len;
            u=ch[u][id];
            ++sz[u];
            for(int j=0;j<maxh;++j)
                if(x&(1<<j)) sum[u][j]++;
        }
    }
    long long getsum(int x)
    {
        long long ans=0;
        for(int i=0;i<maxh;++i)
            if(xortag&(1<<i)) ans+=(sz[x]-sum[x][i])*(1LL<<i);else ans+=sum[x][i]*(1LL<<i);
        return ans;
    }
    long long query(int x)
    {
        if(x==0) return 0;
        int u=root;
        long long ans=0;
        for(int i=maxh-1;i>=0;--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;
    }
    int getsize()
    {
        return sz[ch[root][0]]+sz[ch[root][1]];
    }
}Trie;
struct array
{
    int a[maxn+50];
    int sum[maxn+50][maxh];
    int len=0;
    void insert(int x)
    {
        x^=xortag;
        a[++len]=x;
        for(int i=0;i<maxh;++i)
            sum[len][i]=sum[len-1][i]+((x&(1<<i))>0);
    }
    long long query(int x)
    {
        long long ans=0;
        for(int i=0;i<maxh;++i)
            if(xortag&(1<<i)) ans+=(x-sum[x][i])*(1LL<<i);else ans+=sum[x][i]*(1LL<<i);
        return ans;
    }
    void transfer()
    {
        Trie.tag=xortag;
        for(int i=1;i<=len;++i)
            Trie.insert(a[i]);
        len=0;
    }
}Array;
long long query(int x)
{
    if(x<=Trie.getsize()) return Trie.query(x);
    else return Trie.query(Trie.getsize())+
        Array.query(x-Trie.getsize());
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
    {
        int x;
        scanf("%d",&x);
        Array.insert(x);
    }
    scanf("%d",&m);
    for(int i=1;i<=m;++i)
    {
        int op,x,y;
        scanf("%d",&op);
        if(op==1)
        {
            scanf("%d",&x);
            Array.insert(x);
        }
        if(op==2)
        {
            scanf("%d%d",&x,&y);
            printf("%lld\n",query(y)-query(x-1));
        }
        if(op==3)
        {
            scanf("%d",&x);
            xortag^=x;
        }
        if(op==4) Array.transfer();
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/Kong-Ruo/p/7896105.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值