题意
我有一个数列a[1],a[2],…,a[n],每个a[i]是小于2^m的非负整数。
现在请您实现三种操作,格式说明如下:
1 x y w 对于所有x<=i<=y,将a[i]修改为a[i] xor w;
2 x y w 对于所有x<=i<=y,将a[i]修改为w;
3 从a[1],a[2],…,a[n]中选出若干个数,使它们的xor和最大,并输出这个最大值。
(xor表示按位异或运算)
题解
最近写代码SB错误越来越多了,都要写好几个小时才调完。。
但我的方法确实不优秀。。
先说一个一定要做的转化,就是把序列差分就变成单点修改了
就是你把每个数变成从
[
i
,
j
]
[i,j]
[i,j]这些时刻出现
这个怎么处理自己思考吧
容易发现对于区间赋值后一堆0你不用管,因此有用的数是
n
+
m
n+m
n+m个的
然后后面就有两个做法了
一个是我的超级SB做法。。另外一个是优秀的标解
其实标解的思路我以前见过,但是忘了
先说说我的吧
你可以把区间排序按l端点排序
然后对于每一个位开一个vector
存储他不同时间段时发挥作用的数字是什么
容易发现,每一个数不会被分成超过n段,因此总和是
(
n
+
m
)
n
(n+m)n
(n+m)n的
然后做的时候,你可以还原线性基,就是你找到线性基这一位在这个时间段是哪一个就可以了
以上过程都可以用bitset优化,时空复杂度都是
m
3
/
32
m^3/32
m3/32的
空间巨大
似乎除了可以动态询问前i个答案没什么优点
显然,这个前i个答案可以预处理出来。。
于是就毫无优点了,唯一的优点就是我自己想的。。
第二个做法就简单很多:
区间赋值就相当于删除一些数,修改两个数,修改=删除+插入,瓶颈在于怎么在线性基中删一个数,维护每个数在序列出现的时间区间[li,ri],按时间轴扫过去,在线性基加入一个数时,从高位往低位,若现在可以插入第w位,第w位无值直接插入,有值假设这个值j的区间是[lj,rj],若rj<ri就把j取出来,i插入,把取出来的数接着往下插,这样删除一个数时可以直接从线性基中删掉他,基中没有其他数可以替代他的位置
似乎见过这个思路,但是很久没用过就忘了。。一定要记下来啊。。
附上代码吧(当然是第一种的)
虽然说起来很简单,但细节较多还是调了很久
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<bitset>
#include<vector>
using namespace std;
const int N=2001;
int n,m,q;
char ss[N];
bitset<N> s[N];
bitset<N> a[N];
bitset<N> g;//临时变量
int last[N];//上一个时间点是什么
struct qq
{
int l,r;
bitset<N> h;
}t[N*5];int tot=0;
qq l[N*N/5];
bool ask[N];
bool cmp (qq x,qq y) {return x.l==y.l?x.r<y.r:x.l<y.l;}
vector<int> vec[N];
int id=0;
int now[N];
void prepare ()
{
for (int u=1;u<=tot;u++)
{
for (int i=m-1;i>=0;i--)
{
if (t[u].l>t[u].r) break;
if (t[u].h[i]==1)//这一位有1
{
int siz=vec[i].size();
if (siz==0)
{
id++;
l[id]=t[u];
t[u].r=t[u].l-1;
vec[i].push_back(id);
}
else
{
int R=l[vec[i][siz-1]].r+1;
if (R<=t[u].r)
{
id++;
l[id]=t[u];
l[id].l=max(l[id].l,R);
t[u].r=min(t[u].r,l[id].l-1);
vec[i].push_back(id);
}
t[u].r=min(t[u].r,R-1);
t[u].h=t[u].h^l[vec[i][siz-1]].h;
}
}
}
}
}
void solve ()
{
for (int u=0;u<m;u++) now[u]=0;
for (int u=1;u<=q;u++)
if (ask[u])//这个是要询问的
{
g.reset();
for (int i=m-1;i>=0;i--)
{
int siz=vec[i].size();
while (now[i]<siz)
{
if (l[vec[i][now[i]]].r<u) now[i]++;
else break;
}
if (now[i]>=siz) continue;
if (l[vec[i][now[i]]].l>u) continue;
if (g[i]==0)
{
g=g^l[vec[i][now[i]]].h;
}
}
for (int i=0;i<m;i++)
{
if (g[m-i-1]) printf("1");
else printf("0");
}
printf("\n");
}
}
int main()
{
memset(ask,false,sizeof(ask));
scanf("%d%d%d",&n,&m,&q);
for (int u=1;u<=n;u++)
{
scanf("%s",ss);
for (int i=0;i<m;i++) s[u][m-i-1]=(ss[i]-'0');
a[u]=s[u];
}
for (int u=n;u>=2;u--) s[u]=s[u]^s[u-1];
for (int u=1;u<=n;u++) last[u]=1;
for (int u=1;u<=q;u++)
{
int op;
scanf("%d",&op);
if (op==1)
{
int x,y;
scanf("%d%d",&x,&y);
scanf("%s",ss);
for (int i=0;i<m;i++) g[m-i-1]=(ss[i]-'0');
if (last[x]!=-1) {tot++;t[tot].l=last[x];t[tot].r=u-1;t[tot].h=s[x];}
last[x]=u+1;s[x]=s[x]^g;
y++;
if (y<=n)
{
if (last[y]!=-1) {tot++;t[tot].l=last[y];t[tot].r=u-1;t[tot].h=s[y];}
last[y]=u+1;s[y]=s[y]^g;
}
for (int i=x;i<y;i++) a[i]=a[i]^g;
}
if (op==2)
{
int x,y;
scanf("%d%d",&x,&y);
scanf("%s",ss);
for (int i=0;i<m;i++) g[m-i-1]=(ss[i]-'0');
if (last[x]!=-1) {tot++;t[tot].l=last[x];t[tot].r=u-1;t[tot].h=s[x];last[x]=u;}
last[x]=u+1;s[x]=g^a[x-1];
y++;
if (y<=n)
{
if (last[y]!=-1) {tot++;t[tot].l=last[y];t[tot].r=u-1;t[tot].h=s[y];}
last[y]=u+1;s[y]=g^a[y];
}
for (int i=x;i<y;i++) a[i]=g;
for (int i=x+1;i<y;i++)
{
if (last[i]!=-1)
{
tot++;
t[tot].l=last[i];
t[tot].r=u-1;
t[tot].h=s[i];
s[i].reset();
}
last[i]=-1;
}
}
if (op==3) ask[u]=true;
}
for (int u=1;u<=n;u++)
if (last[u]!=-1)
{
tot++;t[tot].l=last[u];t[tot].r=q;
t[tot].h=s[u];
}
sort(t+1,t+1+tot,cmp);
prepare();
solve();
return 0;
}