题解 P7346 【DSOI 2021】归零
首先,由于修改复杂度较大,所以我们考虑修改打 tag,查询时再求具体值。开一个数组
然后我们对于所有
全部的部分分!
考虑
考虑
如果对应操作是
否则,由于
然鹅由于这题修改是异或,所以一个操作执行偶数次相当于撤销。容易想到把 flg 表示这个修改究竟做没做。于是我们可以
然后还有一些具体细节,看代码。
#include<cstdio>
const int N=1e5+10,M=5e5+10;
int n,m,a[N],b[N],c[N],op[M],x[M],y[M],flg,stk[M],top;
// b 表示常规修改;c 表示 3 操作修改;flg 为 0 表示修改失败,-1 表示修改成功
inline int get(int x)//求当前 a[x]
{
int u,v;
for(u=1,v=a[x];u*u<x;++u)
if(x%u==0)v^=b[u]^b[x/u]^(flg&(c[u]^c[x/u]));
if(u*u==x)v^=b[u]^(flg&c[u]);
return v;
}
int main()
{
int i,u,v;scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)scanf("%d",&a[i]);
for(i=1;i<=m;i++)
{
scanf("%d",&op[i]);
switch(op[i])
{
case 1:
scanf("%d%d",&x[i],&y[i]);
b[x[i]]^=y[i];
break;
case 2:
scanf("%d",&x[i]);
printf("%d\n",get(x[i]));
break;
case 3:
scanf("%d%d%d%d",&x[i],&y[i],&u,&v);
while(top)b[stk[top]]^=flg&c[stk[top]],c[stk[top--]]=0;flg=0;//将之前的修改做了,清空 c 数组
for(;u<=v;u++)if(op[u]==1)c[stk[++top]=x[u]]^=y[u];//开栈记录修改位置
if(get(x[i])<=y[i])flg=-1;
break;
case 4:
scanf("%d",&u);op[i]=op[u];x[i]=x[u];y[i]=y[u];//直接得到对应位置
switch(op[i])
{
case 1:
b[x[i]]^=y[i];
break;
case 2:
printf("%d\n",get(x[i]));
break;
case 3:
if(get(x[i])<=y[i])flg^=-1;//O(1) 修改
}
}
}
return 0;
}