传送门:bzoj5220
题意
给定长度为
的数组
中不超过
个区间(以
满足异或和为
的形式给出),再给定初始值均为
的长度为
的数组
和
次
的加值操作,具体操作为:遍历所有给定的区间,若满足
的区间,则将
全部加上
。
求操作完毕后的
数组。
。
题解
这道题真的是将分块&分类讨论进行到底啊。不仅操作分块,赋值也要分情况讨论,最终将复杂度优化到 。膜了膜 的题解,终于码出来了。
发现网上没什么题解,下面具体讲一下探索解法的过程:
首先考虑如何快速处理出所有满足 的区间。设 ,条件转化为 ,逐个加入 ,存在 里,就可以 处理出来了,记得记录每个位置对应的 的个数(之后的分类讨论会用到)。
发现这样区间数目最坏情况下多达 级别(如全为 的情况)。而加值操作固定为 次。那么考虑牺牲加值操作的复杂度,使得 数组的区间加操作复杂度变为 。
可以将加值操作按 降序排序,倒序遍历 的区间,每次将 的加值操作更新到数组中。而对于每次区间加 的询问,就是查询中 的 。将数组分块,维护加值操作即可。
区间加操作显然可以转换为差分,最后答案求个前缀和即可。这样加值操作总共是 的,单个区间加操作是 的。
下面到了分类讨论环节:
为保证复杂度,将区间加右端点为 对应的可行 个数 和 的情况分别处理。
- 可行 。直接遍历 ,总复杂度 。
- 可行 。直接遍历 复杂度无法保证,而这样的情况出现次数同样 次,那么将所有满足 的区间 提出来,按照以下方法 处理,总复杂度 。
已经将所有 相同且出现次数 的集合提取出来了,现在逐个集合进行处理。
将加值操作拆成 ,设后缀和为 , 即为所有 的区间的权值和。
设可行 有 个,位置存在 数组中,可行 有 个,位置存在 数组中。那么考虑对于一个区间加操作 中 究竟加/减了哪些值。
需要维护6种前缀/后缀和,在这里先列出:
- :前缀可行 个数
- :前缀可行 个数
- :
- :
- :
- :
对于每个 ,加上 ,但这样把 的也加上了,所以减去 。
对于每个 ,减去 ,但同样把 的也减去了,所以加上 。
~ 可以 处理出来,多了几遍循环,常数略大。
这样就做完了,代码实现如同上述。
按照 判断会 ,玄学调参设成 就过了。
做这种题一定要有耐心,想清楚流程写在纸上以后再打代码。。。
代码
#include<bits/stdc++.h>
#define RI register
#define gc getchar()
#define si isdigit(cc)
using namespace std;
const int N=150050,mod=1<<30;
int n,m,kk,block;
int kl[400],kr[400],in[N],cg[400],val[N];
int a[N],to[N],dir[N],d[N];
int ban[N],ans[N],s[7][N],ql[N],qr[N],nl,nr;
map<int,int>mp;
queue<int>que;
struct P{
int st,ed,w;
bool operator <(const P&A)const{
return A.ed<ed;
}
}op[N];
char cc;
inline void rd(int &x)
{
cc=gc;x=0;
for(;!si;cc=gc);
for(;si;cc=gc) x=x*10+(cc^48);
}
inline int ad(int x,int y){x+=y;return x>=mod?x-mod:x;}
inline int dc(int x,int y){x-=y;return x<0?x+mod:x;}
inline int mul(int x,int y){return 1ll*x*y%mod;}
inline void init()
{
RI int i,j,dif,sim;
rd(n);rd(m);rd(kk);
block=sqrt(n)+1;
for(i=1;i<=n;++i) in[i]=(i-1)/block+1;
for(i=in[n];i;--i)
kl[i]=(i-1)*block+1,kr[i]=block*i;
kr[in[n]]=min(kr[in[n]],n);
for(i=1;i<=n;++i){
rd(a[i]);a[i]^=a[i-1];//前缀异或和
sim=mp[a[i]];dif=mp[kk^a[i]];//找到最近的相同的,互补的
to[i]=sim;dir[i]=dif;d[i]=d[sim]+1;//s[i]出现的第d[i]次
mp[a[i]]=i;
}
for(i=1;i<=m;++i)
rd(op[i].st),rd(op[i].ed),rd(op[i].w);
sort(op+1,op+m+1);
}
//分块加值
inline void insert(P e)
{
int i,l=e.st,r=e.ed,lim,ads=e.w;
if(l!=kl[in[l]] || r<kr[in[l]]){
lim=min(kr[in[l]],r);
for(i=l;i<=lim;++i) val[i]=ad(val[i],ads);
}else cg[in[l]]=ad(cg[in[l]],ads);
if(in[l]==in[r]) return;
if(r!=kr[in[r]]){
for(i=kl[in[r]];i<=r;++i) val[i]=ad(val[i],ads);
}else cg[in[r]]=ad(cg[in[r]],ads);
for(i=in[l]+1;i<in[r];++i) cg[i]=ad(cg[i],ads);
}
//<=700
inline void fwork()
{
RI int i,j,k,t;
for(i=n,j=1;i;--i){
for(;j<=m && op[j].ed==i;++j) insert(op[j]);
//推迟处理
if(ban[i]) {ban[to[i]]=1;continue;}
if(d[dir[i]]>700){
ban[i]=ban[to[i]]=1;
que.push(i);
continue;
}
for(k=dir[i];k;k=to[k]){
t=ad(val[k+1],cg[in[k+1]]);
ans[k+1]=ad(ans[k+1],t);
ans[i+1]=dc(ans[i+1],t);
}
//注意特判
if(a[i]==kk){
t=ad(val[1],cg[1]);
ans[1]=ad(ans[1],t);
ans[i+1]=dc(ans[i+1],t);
}
}
}
//>700
inline void pwork()
{
RI int i,j,x,tp,pa,pb,pc;
for(i=1;i<=m;++i){
pa=op[i].st;pb=op[i].ed;pc=op[i].w;
s[5][pb]=ad(s[5][pb],pc);
s[5][pa-1]=dc(s[5][pa-1],pc);
}
for(i=n-1;i;--i) s[5][i]=ad(s[5][i],s[5][i+1]);
for(;!que.empty();){
x=que.front();que.pop();
nr=d[x];
for(tp=x,i=nr;i;--i,tp=to[tp]) qr[i]=tp;
tp=dir[x];nl=d[tp];
if(a[x]==kk) nl++;
for(i=nl;i;--i,tp=to[tp]) ql[i]=tp+1;
if(a[x]==kk) ql[1]=1;
s[0][0]=s[1][0]=0;
pa=pb=1;
for(i=1;i<=n;++i){
s[0][i]=s[0][i-1];s[1][i]=s[1][i-1];
for(;pa<=nl && ql[pa]==i;++pa) s[0][i]++;
for(;pb<=nr && qr[pb]==i;++pb) s[1][i]++;
}
memset(s[2],0,sizeof(int)*(n+3));
memset(s[3],0,sizeof(int)*(n+3));
for(i=1;i<=m;++i){
pa=op[i].st;pb=op[i].ed;pc=op[i].w;
s[2][pa-1]=ad(s[2][pa-1],mul(s[1][pb]-s[1][pa-1],pc));
pc=mul(pc,s[0][pa-1]);
s[3][pa]=ad(s[3][pa],pc);
s[3][pb+1]=dc(s[3][pb+1],pc);
}
s[2][n+1]=s[4][n+1]=0;pb=nr;
for(i=n;i;--i){
s[4][i]=s[4][i+1];s[2][i]=ad(s[2][i],s[2][i+1]);
for(;pb>0 && qr[pb]==i;pb--) s[4][i]=ad(s[4][i],s[5][i]);
}
for(i=1;i<=n;++i) s[3][i]=ad(s[3][i],s[3][i-1]);
for(i=1;i<=nl;++i)
ans[ql[i]]=ad(ans[ql[i]],dc(s[4][ql[i]],s[2][ql[i]]));
for(i=1;i<=nr;++i)
ans[qr[i]+1]=ad(ans[qr[i]+1],dc(s[3][qr[i]],mul(s[0][qr[i]],s[5][qr[i]])));
}
}
inline void print()
{
for(RI int i=1;i<=n;++i){
ans[i]=ad(ans[i],ans[i-1]);
printf("%d ",ans[i]);
}
}
int main(){
init();
fwork();
pwork();
print();
return 0;
}