「LibreOJ β Round #2」计算几何瞎暴力

https://loj.ac/problem/517

题解

首先我们如果没有排序这个骚操作的话,可以直接记一下各个数位的前缀和,然后异或标记给全局打,查询的时候先把区间信息提取出来然后整体异或就好了。

对于排序,我们考虑对所有排好序的节点建\(trie\)树,这样即使有全局异或标记,我们也可以在\(trie\)树上完成前缀信息的查询。

然后就做完了。

代码

#include<bits/stdc++.h>
#define N 200009
#define ls ch[cnt][0]
#define rs ch[cnt][1]
using namespace std;
typedef long long ll;
const int maxn=30;
int a[N],n,q;
int ch[N*maxn][2],ct[N*maxn][maxn],size[N*maxn],sm[N][maxn];
int tot,rot;
int tag,nowtag;
ll ton[32],nw;
inline ll rd(){
    ll x=0;char c=getchar();bool f=0;
    while(!isdigit(c)){if(c=='-')f=1;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    return f?-x:x;
}
void ins(int &cnt,int x,int p){
    if(!cnt)cnt=++tot;
    size[cnt]++;
    for(int i=0;i<=29;++i)if((1<<i)&x)ct[cnt][i]++;
    if(p<0)return;
    int o=(x&(1<<p))!=0;
    if(o)ins(rs,x,p-1);
    else ins(ls,x,p-1);
}
inline ll getsum(int now){
    memset(ton,0,sizeof(ton));
    if(now>=nw){
        for(int i=0;i<=29;++i)ton[i]+=sm[now][i];
    }
    else{
        int cnt=rot,siz=now;
        for(int i=29;i>=0;--i){
            int lson=ls,rson=rs;
            if(nowtag&(1<<i))swap(lson,rson);
            if(size[lson]>=siz)cnt=lson;
            else{
                for(int j=0;j<=29;++j)ton[j]+=ct[lson][j];
                siz-=size[lson];
                cnt=rson;
            }
        }
        if(siz){
            for(int i=0;i<=29;++i)ton[i]+=(ct[cnt][i]!=0)*siz;
        }
    }
    ll ans=0;
    for(int i=0;i<=29;++i){
        ll ss;
        if(tag&(1<<i))ss=now-ton[i];else ss=ton[i];
    //  cout<<ss<<" ";
        ans+=ss*(1ll<<i);
    }
    //cout<<"??\n";
    return ans;
}
int main(){
//  freopen("1.txt","r",stdin);
//  freopen("out","w",stdout);
    n=rd();
    nw=1;
    for(int i=1;i<=n;++i){
      a[i]=rd();
      for(int j=0;j<=29;++j)sm[i][j]=sm[i-1][j]+((a[i]&(1<<j))!=0);
    }
    q=rd();
    int opt,x,l,r;
    while(q--){
        opt=rd();
        if(opt==1){
            x=rd();x^=tag;
            ++n;a[n]=x;
            for(int j=0;j<=29;++j)sm[n][j]=sm[n-1][j]+((a[n]&(1<<j))!=0);
        }
        else if(opt==2){
            l=rd();r=rd();
            printf("%lld\n",getsum(r)-getsum(l-1));
        }
        else if(opt==3)tag^=rd();
        else if(opt==4){
            nowtag=tag;
            while(nw<=n)ins(rot,a[nw],29),nw++;
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/ZH-comld/p/11093089.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值