题解 P5607 【[Ynoi2013] 无力回天 NOI2017】
这是一道在 中很水的题。
题意
求作一种数据结构,支持区间异或,区间查询任意个数异或所给数的最大值。
思路
显然,第二个操作可以简单地使用数据结构 线性基 维护。
但是我们还有修改操作...
由于线性基不支持修改、删除,于是区间异或就很难处理。
于是我们思考差分,使区间修改 -> 单点修改。
另 ,于是区间修改操作 就转变为了两次单点修改 。
很显然 数组可以使用树状数组维护。
然后转为单点修改,可以考虑使用分块/线段树维护,其中每个节点维护的是包含 区间中的 数组构成的线性基。
于是我一开始打出了分块,于是我打出了分块,疯狂卡常,还是 没卡过 ...
后来放弃了,我就开始打线段树,结果一次过...
为什么会这样呢?分块的复杂度为 ,而线段树的复杂度为 由于一个 比一个 小很多,所以运行起来会快很多。
所以得出结论,以后合并节点的复杂度高时不要用分块,要用线段树。
下面给出代码:
分块:
#include <bits/stdc++.h>
using namespace std;
namespace IO{
int len=0;
char ibuf[18<<20],*ss,out[(1<<22)+1];
inline int read(){
register int u=0;
while(*ss<48) ss++;
while(*ss>32)
u=u*10+*ss++-48;
return u;
}
inline void write(int x){
if(x>9)write(x/10);
out[len++]=x%10+48;
}
}
using namespace IO;
struct Linebase{
int sz,p[30];
Linebase(){
p[0]=0;
p[1]=0;
p[2]=0;
p[3]=0;
p[4]=0;
p[5]=0;
p[6]=0;
p[7]=0;
p[8]=0;
p[9]=0;
p[10]=0;
p[11]=0;
p[12]=0;
p[13]=0;
p[14]=0;
p[15]=0;
p[16]=0;
p[17]=0;
p[18]=0;
p[19]=0;
p[20]=0;
p[21]=0;
p[22]=0;
p[23]=0;
p[24]=0;
p[25]=0;
p[26]=0;
p[27]=0;
p[28]=0;
p[29]=0;
sz=0;
}
inline friend Linebase operator +(Linebase a,int b){
if(a.sz==30||!b) return a;
for(register int i=29;i>=0;i--){
if(b>>i&1){
if(a.p[i]){
b^=a.p[i];
}else{
a.p[i]=b;
a.sz++;
return a;
}
}
}
return a;
}
inline friend Linebase operator +(Linebase a,Linebase b){
if(a.sz==30) return a;
if(b.sz==30) return b;
for(register int i=29;i>=0;i--){
if(b.p[i])a=a+b.p[i];
}
return a;
}
inline int getmax(int v){
v=max(v,v^p[29]);
v=max(v,v^p[28]);
v=max(v,v^p[27]);
v=max(v,v^p[26]);
v=max(v,v^p[25]);
v=max(v,v^p[24]);
v=max(v,v^p[23]);
v=max(v,v^p[22]);
v=max(v,v^p[21]);
v=max(v,v^p[20]);
v=max(v,v^p[19]);
v=max(v,v^p[18]);
v=max(v,v^p[17]);
v=max(v,v^p[16]);
v=max(v,v^p[15]);
v=max(v,v^p[14]);
v=max(v,v^p[13]);
v=max(v,v^p[12]);
v=max(v,v^p[11]);
v=max(v,v^p[10]);
v=max(v,v^p[9]);
v=max(v,v^p[8]);
v=max(v,v^p[7]);
v=max(v,v^p[6]);
v=max(v,v^p[5]);
v=max(v,v^p[4]);
v=max(v,v^p[3]);
v=max(v,v^p[2]);
v=max(v,v^p[1]);
v=max(v,v^p[0]);
return v;
}
};
int t[50010],n,m,a[50010],block,belong[50010],cnt;
inline void upd(int x,int k){
for(register int i=x;i<=n;i+=(i&-i)){
t[i]^=k;
}
}
inline int query(int x){
register int ans=0;
for(register int i=x;i>=1;i-=(i&-i)){
ans^=t[i];
}
return ans;
}
struct Block{
int l,r;
Linebase s;
Block(){l=r=0;}
inline void cg(){
s=Linebase();
register int i=l;
for(;i+7<=r;i+=8){
s=s+a[i];
s=s+a[i+1];
s=s+a[i+2];
s=s+a[i+3];
s=s+a[i+4];
s=s+a[i+5];
s=s+a[i+6];
s=s+a[i+7];
}
for(;i<=r;i++){
s=s+a[i];
}
}
}b[150];
inline void modify(int p,int k){
register int bl=belong[p];
a[p]^=k;
b[bl].cg();
}
inline Linebase query(int l,int r){
register int bl=belong[l],br=belong[r];
Linebase c;
if(bl==br){
for(int i=l;i<=r;i++){
c=c+a[i];
}
return c;
}
for(int i=l;i<=b[bl].r;i++){
c=c+a[i];
}
for(int i=bl+1;i<=br-1;i++){
c=c+b[i].s;
}
for(int i=b[br].l;i<=r;i++){
c=c+a[i];
}
return c;
}
int main(){
fread(ss=ibuf,1,18<<20,stdin);
n=read(),m=read();
for(register int i=1;i<=n;i++){
a[i]=read();
}
for(register int i=n;i>=2;i--){
a[i]^=a[i-1];
}
for(register int i=1;i<=n;i++){
upd(i,a[i]);
}
block=13*sqrt(n)/8;
for(register int i=1;i<=n;i+=block){
cnt++;
b[cnt].l=i;
b[cnt].r=min(i+block-1,n);
}
for(register int i=1;i<=cnt;i++){
for(register int j=b[i].l;j<=b[i].r;j++){
b[i].s=b[i].s+a[j];
belong[j]=i;
}
}
while(m--){
register int opt=read(),l=read(),r=read(),v=read();
if(opt==1){
if(belong[l]!=belong[r]){
upd(l,v);
modify(l,v);
if(r<n){
upd(r+1,v);
modify(r+1,v);
}
}else{
a[l]^=v;
upd(l,v);
if(r<n){
a[r+1]^=v;
upd(r+1,v);
}
b[belong[l]].cg();
}
}else{
register int k=query(l);
if(l==r){
write(max(v,v^k));
out[len++]='\n';
}else{
Linebase c=query(l+1,r)+k;
write(c.getmax(v));
out[len++]='\n';
}
}
}
fwrite(out,1,len,stdout);
return 0;
}
/*
Time:27.32s
Memory:7.20MB
TLE 3.07s on Test #9
95pts
*/
线段树:
#include <bits/stdc++.h>
using namespace std;
namespace IO{
int len=0;
char ibuf[18<<20],*ss,out[(1<<22)+1];
inline int read(){
register int u=0;
while(*ss<48) ss++;
while(*ss>32)
u=u*10+*ss++-48;
return u;
}
inline void write(int x){
if(x>9)write(x/10);
out[len++]=x%10+48;
}
}
using namespace IO;
struct Linebase{
int sz,p[30];
Linebase(){
p[0]=0;
p[1]=0;
p[2]=0;
p[3]=0;
p[4]=0;
p[5]=0;
p[6]=0;
p[7]=0;
p[8]=0;
p[9]=0;
p[10]=0;
p[11]=0;
p[12]=0;
p[13]=0;
p[14]=0;
p[15]=0;
p[16]=0;
p[17]=0;
p[18]=0;
p[19]=0;
p[20]=0;
p[21]=0;
p[22]=0;
p[23]=0;
p[24]=0;
p[25]=0;
p[26]=0;
p[27]=0;
p[28]=0;
p[29]=0;
sz=0;
}
inline void insert(int b){
if(sz==30||!b) return ;
for(register int i=29;i>=0;i--){
if(b>>i&1){
if(p[i]){
b^=p[i];
}else{
p[i]=b;
sz++;
return ;
}
}
}
return ;
}
inline friend Linebase operator +(Linebase a,Linebase b){
if(a.sz==30) return a;
if(b.sz==30) return b;
for(register int i=29;i>=0;i--){
if(b.p[i])a.insert(b.p[i]);
}
return a;
}
inline int getmax(int v){
v=max(v,v^p[29]);
v=max(v,v^p[28]);
v=max(v,v^p[27]);
v=max(v,v^p[26]);
v=max(v,v^p[25]);
v=max(v,v^p[24]);
v=max(v,v^p[23]);
v=max(v,v^p[22]);
v=max(v,v^p[21]);
v=max(v,v^p[20]);
v=max(v,v^p[19]);
v=max(v,v^p[18]);
v=max(v,v^p[17]);
v=max(v,v^p[16]);
v=max(v,v^p[15]);
v=max(v,v^p[14]);
v=max(v,v^p[13]);
v=max(v,v^p[12]);
v=max(v,v^p[11]);
v=max(v,v^p[10]);
v=max(v,v^p[9]);
v=max(v,v^p[8]);
v=max(v,v^p[7]);
v=max(v,v^p[6]);
v=max(v,v^p[5]);
v=max(v,v^p[4]);
v=max(v,v^p[3]);
v=max(v,v^p[2]);
v=max(v,v^p[1]);
v=max(v,v^p[0]);
return v;
}
};
int t[50010],n,m,a[50010],block,belong[50010],cnt;
inline void upd(int x,int k){
for(register int i=x;i<=n;i+=(i&-i)){
t[i]^=k;
}
}
inline int query(int x){
register int ans=0;
for(register int i=x;i>=1;i-=(i&-i)){
ans^=t[i];
}
return ans;
}
struct Seg_tree{
Linebase b[200010];
inline void build(int l,int r,int rt){
for(int i=l;i<=r;i++){
b[rt].insert(a[i]);
}
if(l==r) return;
int mid=l+r>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
}
inline void modify(int pos,int l,int r,int rt,int k){
if(l==r){
b[rt]=Linebase();
a[l]^=k;
b[rt].insert(a[l]);
return ;
}
int mid=l+r>>1;
if(pos<=mid) modify(pos,l,mid,rt<<1,k);
else modify(pos,mid+1,r,rt<<1|1,k);
b[rt]=b[rt<<1]+b[rt<<1|1];
}
inline Linebase query(int ql,int qr,int rt,int l,int r){
if(ql==l&&qr==r) return b[rt];
int mid=ql+qr>>1;
if(mid>=r) return query(ql,mid,rt<<1,l,r);
else if(mid<l) return query(mid+1,qr,rt<<1|1,l,r);
else return query(ql,mid,rt<<1,l,mid)+query(mid+1,qr,rt<<1|1,mid+1,r);
}
}T;
int main(){
fread(ss=ibuf,1,18<<20,stdin);
n=read(),m=read();
for(register int i=1;i<=n;i++){
a[i]=read();
}
for(register int i=n;i>=2;i--){
a[i]^=a[i-1];
}
for(register int i=1;i<=n;i++){
upd(i,a[i]);
}
T.build(1,n,1);
while(m--){
register int opt=read(),l=read(),r=read(),v=read();
if(opt==1){
upd(l,v);
T.modify(l,1,n,1,v);
if(r<n){
upd(r+1,v);
T.modify(r+1,1,n,1,v);
}
}else{
register int k=query(l);
if(l==r){
write(max(v,v^k));
out[len++]='\n';
}else{
Linebase c=T.query(1,n,1,l+1,r);
c.insert(k);
write(c.getmax(v));
out[len++]='\n';
}
}
}
fwrite(out,1,len,stdout);
return 0;
}
/*
Time:7.25s
Memory:31.10MB
AC
100pts
*/
这是我做的第四道 ,写的第一篇 题解,希望大家支持,谢谢。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通