51nod 1577 异或凑数 线性基的妙用

\(OTZgengyf\)。。当场被吊打\(QwQ\)


思路:线性基

提交:\(3\)

错因:往里面加数时\(tmp.p\)\(i\)区分不清(还是我太菜了)

题解:

我们对每个位置的线性基如此操作:
对于每一位,保存尽量靠后的数;
所以每一位还要记录位置。
(后文区分"位"(二进制位)和"位置"(原数组中的第几位),每个位置都有\(30\)位)
具体来说,就是从高位向低位扫,如果我们当前的数能被放入某一位,如果这一位没有数,则直接放入;否则比较出现位置,如果当前数出现位置较为靠后,就把当前数和这一位的数交换,然后从下一位继续进行插入。这样高位上的数会出现的尽量靠后。
查询的时候,从高位到低位进行查询。如果需要某位上面的数而这个数出现的位置\(<l\),直接输出'NO'。

#include<cstdio>
#include<iostream>
#define R register int
using namespace std;
namespace Luitaryi {
static char B[1<<15],*S=B,*T=B;
#define getchar() (S==T&&(T=(S=B)+fread(B,1,1<<15,stdin),S==T)?EOF:*S++)
template<class I> inline I g(I& x) { x=0;
  register I f=1; register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
  do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*=f;
} const int N=5e5+10;
#define pc(x) putchar(x)
struct node {int c,p; node() {}
  node(int _c,int _p):c(_c),p(_p) {}
}f[N][31];
int n,m;
inline void main() {
  g(n); for(R i=1,x;i<=n;++i) { 
    g(x); register node tmp(x,i);
    memcpy(f[i],f[i-1],sizeof(f[i-1]));
    for(R k=30;~k;--k) if(tmp.c&(1<<k)) {
      if(!f[i][k].c) {
        f[i][k].c=tmp.c,f[i][k].p=tmp.p; break;
      } else {
        if(f[i][k].p<tmp.p) swap(tmp.c,f[i][k].c),swap(f[i][k].p,tmp.p);
        tmp.c^=f[i][k].c;
      }
    }
  } g(m); for(R i=1,l,r,x;i<=m;++i) {
    g(l),g(r),g(x);
    for(R k=30;~k;--k) if(x&(1<<k)) {
      if(!f[r][k].c||f[r][k].p<l) {
        pc('N'),pc('O'),pc('\n'); goto end;
      } x^=f[r][k].c;
    } pc('Y'),pc('E'),pc('S'); pc('\n'); end:;
  }
}
} signed main() {Luitaryi::main(); return 0;}

2019.08.12
88

转载于:https://www.cnblogs.com/Jackpei/p/11337440.html

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值