题解:P8526 [Ynoi2078] 《How to represent part-whole hierarchies in a neural network》阅读报告(更新中...)
一句话题意:静态查询子区间颜色数量异或和。
一般颜色数量显然使用扫描线维护第一次最后一次出现。在本题似乎没有更好的利用方式了,所以直接扫描
那么问题被化为了区间加
一个简单的思路是使用序列分块进行扫描线。考虑序列分块要维护的是啥。
不论整散块,区间加
整块每次需要
但预处理显然不可能对
这个东西显然已经可以在
发现散块唯一难点在于更新历史版本。然而观察后发现,更新单点历史版本的操作与
考虑优化求
子问题的具体实现可以参考代码。
void solve(int len)
{
memset(dp[V],0,sizeof dp[V]);
for(int i=1;i<=len;i++)
dp[V][A[i]]^=1;
for(int i=V-1;i>=0;i--)
{
for(int j=0;j<(1<<i);j++)
dp[i][j]=dp[i+1][j]^dp[i+1][j+(1<<i)];
}//dp[i][j]表示%2^i=j数量
for(int i=V;i>=0;i--)
{
for(int j=(1<<i)-1;j>=1;j--)
dp[i][j-1]^=dp[i][j];
}//dp[i][j]表示%2^i>=j数量
for(int i=0;i<V;i++)
{
for(int j=0;j<(1<<i+1);j++)
f[i+1][j]=dp[i+1][2*(1<<i)-j];
for(int j=(1<<i)+1;j<(1<<i+1);j++)
f[i+1][j]^=dp[i+1][3*(1<<i)-j];
for(int j=0;j<(1<<i);j++)
f[i+1][j]^=dp[i+1][(1<<i)-j];
for(int j=(1<<i);j<(1<<i+1);j++)
f[i+1][j]^=dp[i+1][0];
//f_x表示%2^(i+1)=x的x第i位是否为1
for(int j=0;j<(1<<i);j++)
f[i+1][j]=(f[i+1][j]<<i)|f[i][j],f[i+1][j+(1<<i)]=(f[i+1][j+(1<<i)]<<i)|f[i][j];
//f_x表示%2^(i+1)=x的前i位
}
for(int i=0;i<(1<<V);i++)
as[i]=f[V][i];
return;
}
给出完整代码实现。
#include<bits/stdc++.h>
using namespace std;
const int N=400010,V=8,B=(1<<V);
struct node
{
int id,l,r;
}qu[400010];
bool cmp(node x,node y)
{
return x.r<y.r;
}
int c[400010],aa[400010];
int A[B+5];
bool dp[(1<<V+1)+5];
uint8_t f[(1<<V+1)+5],g[(1<<V)+5];
template<int I>void AAAAA()
{
for(int j=(1<<I);j<(2<<I);j++)dp[j]=dp[j+(1<<I)]^dp[j+(2<<I)];
}
template<int I>void BBBBB()
{
for(int j=(2<<I)-1;j>=(1<<I)+1;j--)dp[j-1]^=dp[j];
}
template<int I>void CCCCC()
{
for(int j=0;j<(1<<I);j++)
g[j]=dp[j+(2<<I)]^dp[j+(3<<I)];
g[(1<<I)]=g[0]^dp[(2<<I)];
for(int j=0;j<(1<<I);j++)
f[j]|=g[(1<<I)-j]<<I;
for(int j=0;j<(1<<I);j++)
f[j+(1<<I)]=f[j]^(dp[(2<<I)]<<I);
}
void solve(int len,int op)
{
f[0]=0;
if(op)
{
memset(dp+(1<<V),0,sizeof(bool)*(1<<V));
for(int i=1;i<=len;i++)
dp[A[i]+(1<<V)]^=1;
}
AAAAA<7>();
AAAAA<6>();
AAAAA<5>();
AAAAA<4>();
AAAAA<3>();
AAAAA<2>();
AAAAA<1>();
AAAAA<0>();
BBBBB<8>();
BBBBB<7>();
BBBBB<6>();
BBBBB<5>();
BBBBB<4>();
BBBBB<3>();
BBBBB<2>();
BBBBB<1>();
BBBBB<0>();
CCCCC<0>();
CCCCC<1>();
CCCCC<2>();
CCCCC<3>();
CCCCC<4>();
CCCCC<5>();
CCCCC<6>();
CCCCC<7>();
}
int n,m,a[400010],b[400010],ini[N/B+5][(1<<V)+5],sum[N/B+5],add[N/B+5];
bool tag[N/B+5][(1<<V)+5];
void rebuildb(int id)//借助tag更新出块中所有的b,并加入到块历史异或和sum中,并清空tag
{
int len=0;
memcpy(dp+(1<<V),tag[id],sizeof tag[id]);
int l=max(id*B,1),r=min((id+1)*B-1,n);
for(int i=1;i<(1<<V);i++)
tag[id][i]^=tag[id][i-1];//tag_i表示<=i的数量
solve(len,0);
len=tag[id][(1<<V)-1];
if(len==0)
{
for(int i=l;i<=r;i++)
{
int op=a[i]&((1<<V)-1),x1=tag[id][(1<<V)-1-op];
b[i]^=f[op];
if(x1&1)
b[i]^=(a[i]^op)^((a[i]^op)+(1<<V));
}
}
else
{
for(int i=l;i<=r;i++)
{
int op=a[i]&((1<<V)-1),x1=tag[id][(1<<V)-1-op];
b[i]^=f[op];
if(x1&1)
b[i]^=(a[i]^op);
else
b[i]^=(a[i]^op)+(1<<V);
}
}
memset(tag[id],0,sizeof tag[id]);
return;
}
void init(int id)//只需求出ini即可
{
memset(ini[id],0,sizeof ini[id]);
int l=max(id*B,1),r=min((id+1)*B-1,n);
for(int i=l;i<=r;i++)
{
int op=a[i]&((1<<V)-1);
ini[id][0]^=a[i]-op;
ini[id][(1<<V)-op]^=(a[i]-op)^(a[i]-op+(1<<V));
A[i-l+1]=op;
}
for(int i=1;i<(1<<V);i++)
ini[id][i]^=ini[id][i-1];
solve(r-l+1,1);
for(int i=0;i<(1<<V);i++)
ini[id][i]^=f[i];
return;
}
void rebuild(int id,int l,int r,int op)
{
if(add[id]==0&&tag[id][add[id]]==0&&l>r)
return;
int L=max(id*B,1),R=min((id+1)*B-1,n);
if(add[id]!=0||tag[id][add[id]]!=0)
rebuildb(id);
for(int i=L;i<=R;i++)
a[i]+=add[id];
for(int i=l;i<=r;i++)
a[i]++;
add[id]=0;
if(op==1)
init(id);
else
{
ini[id][0]=0;
for(int i=L;i<=r;i++)
ini[id][0]^=a[i];
}
return;
}
void update(int l,int r)
{
if(l/B==r/B)
{
int id=l/B;
rebuild(id,l,r,r%B==B-1);
return;
}
int lid=l/B,rid=r/B;
rebuild(lid,l,min((lid+1)*B-1,n),1);
rebuild(rid,max(rid*B,1),r,r%B==B-1);
for(int i=lid+1;i<rid;i++)
add[i]++;
return;
}
inline void uphis(int id)
{
tag[id][add[id]]^=1;
sum[id]^=ini[id][add[id]];
if(add[id]==(1<<V)-1)
rebuild(id,1,0,1);
return;
}
int query(int l,int r)
{
if(l/B==r/B)
{
int ans=0;
rebuild(l/B,1,0,r%B==B-1);
for(int i=l;i<=r;i++)
ans^=b[i];
return ans;
}
int ans=0,lid=l/B,rid=r/B;
rebuild(lid,1,0,1);
rebuild(rid,1,0,r%B==B-1);
for(int i=l;i<=min((lid+1)*B-1,n);i++)
ans^=b[i];
for(int i=max(rid*B,1);i<=r;i++)
ans^=b[i];
for(int i=lid+1;i<rid;i++)
ans^=sum[i];
return ans;
}
int lastans[N+5];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++)
cin>>a[i],aa[i]=a[i];
int l,r;
for(int i=1;i<=m;i++)
{
cin>>l>>r;
qu[i]={i,l,r};
}
sort(qu+1,qu+m+1,cmp);
memset(a,0,sizeof a);
for(int i=0,j=0;i<=n;i++)
{
if(i)
{
update(c[aa[i]]+1,i);//区间加
c[aa[i]]=i;
}
for(int id=0;id<=i/B;id++)
uphis(id);
while(j<m&&qu[j+1].r<=i)
{
j++;
lastans[qu[j].id]^=query(qu[j].l,i);
}
}
for(int i=1;i<=m;i++)
cout<<lastans[i]<<'\n';
return 0;
}