codechef minxor

分块,每个块开一棵字典树,暴力询问,修改时没有被完整覆盖的块暴力重构



code:

#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;

const int maxn = 300005;
const int maxnn = 3100;

int N=500,n,m;
int a[maxn],ans1,ans2;
int id[maxn],st[maxnn],f[maxnn],root[maxnn],cnt[maxnn];
int tr[maxn*20][2],sum[maxn*20]; 
void build_(int x)
{
    int tot=cnt[x];
    for(;tot>=root[x];tot--) tr[tot][0]=tr[tot][1]=sum[tot]=0;
    tot++;
    for(int i=st[x];i<st[x+1];i++) a[i]^=f[x]; f[x]=0;
    for(int i=st[x];i<st[x+1];i++)
    {
        int p=root[x];
        for(int j=15;j>=0;j--)
        {
            int y=((a[i]&(1<<j))!=0);
            if(!tr[p][y]) tr[p][y]=++tot;
            p=tr[p][y];
        }
        sum[p]++;
    }
    cnt[x]=tot;
}
void find_(int bel)
{
    int x=root[bel]; int now=0;
    for(int i=15;i>=0;i--)
    {
        int y=((f[bel]&(1<<i))!=0);
        if(tr[x][y])x=tr[x][y];
        else x=tr[x][y^1],now+=1<<i;
        if(now>ans1)return ;
    }
    if(now<ans1) ans1=now,ans2=0;
    if(now==ans1) ans2+=sum[x];
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        id[i]=(i-1)/N+1;
        scanf("%d",&a[i]);
    }
    for(int i=1;i<=id[n];i++)
        st[i]=(i-1)*N+1,cnt[i]=root[i]=st[i]*20;
    st[id[n]+1]=n+1; root[id[n]+1]=cnt[id[n]+1]=(n+1)*20;
    for(int i=1;i<=id[n];i++) build_(i);
    while(m--)
    {
        int l; scanf("%d",&l);
        if(l==1)
        {
            int x,y;scanf("%d%d",&x,&y);
            int t1=id[x],t2=id[y];
            ans1=65536,ans2=0;
            if(t1==t2)
            {
                for(int i=x;i<=y;i++)
                {
                    if((a[i]^f[t1])<ans1) ans1=a[i]^f[t1],ans2=0;
                    if((a[i]^f[t1])==ans1) ans2++;
                }
            }
            else
            {
                for(int i=x;i<st[t1+1];i++)
                {
                    if((a[i]^f[t1])<ans1) ans1=a[i]^f[t1],ans2=0;
                    if((a[i]^f[t1])==ans1) ans2++;
                }
                for(int i=st[t2];i<=y;i++)
                {
                    if((a[i]^f[t2])<ans1) ans1=a[i]^f[t2],ans2=0;
                    if((a[i]^f[t2])==ans1) ans2++;
                }
                for(int i=t1+1;i<t2;i++) find_(i);
            }
            printf("%d %d\n",ans1,ans2);
        }
        else
        {
            int x,y,c;scanf("%d%d%d",&x,&y,&c);
            int t1=id[x],t2=id[y];
            if(t1==t2)
            {
                for(int i=x;i<=y;i++) a[i]^=c;
                build_(t1);
            }
            else
            {   
                for(int i=x;i<st[t1+1];i++) a[i]^=c;
                for(int i=st[t2];i<=y;i++) a[i]^=c;
                build_(t1); build_(t2);
                for(int i=t1+1;i<t2;i++) f[i]^=c;
            }
        }
    }

    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值