传送门:bzoj5220
给定长度为 n n n的数组 a a a中不超过 n 2 n^2 n2个区间(以 l , r l,r l,r满足异或和为 k k k的形式给出),再给定初始值均为 0 0 0的长度为 n n n的数组 b b b和 m m m次 ( s t , e d , w ) (st,ed,w) (st,ed,w)的加值操作,具体操作为:遍历所有给定的区间,若满足 l ≥ s t , r ≤ e d l\geq st,r\leq ed l≥st,r≤ed的区间,则将 b l , b l + 1 , . . . , b r b_l,b_{l+1},...,b_r bl,bl+1,...,br全部加上 w w w。
求操作完毕后的 b b b数组。
n , m ≤ 150000 , a i < 2 30 n,m\leq 150000,a_i< 2^{30} n,m≤150000,ai<230。
这道题真的是将分块&分类讨论进行到底啊。不仅操作分块,赋值也要分情况讨论,最终将复杂度优化到 O ( ( n + m ) n ) O((n+m)\sqrt n) O((n+m)n)。膜了膜 C l a r i s Claris Claris的题解,终于码出来了。
发现网上没什么题解,下面具体讲一下探索解法的过程:
首先考虑如何快速处理出所有满足 a l x o r a l + 1 . . . x o r a r = k a_l xora_{l+1}...xora_r=k alxoral+1...xorar=k的区间。设 t i = a 1 x o r a 2 . . . x o r a i t_i=a_1xora_2...xora_i ti=a1xora2...xorai,条件转化为 t r x o r t l − 1 = k t_rxort_{l-1}=k trxortl−1=k,逐个加入 t i t_i ti,存在 m a p map map里,就可以 n l o g n nlogn nlogn处理出来了,记得记录每个位置对应的 k x o r t i kxor{t_i} kxorti的个数(之后的分类讨论会用到)。
发现这样区间数目最坏情况下多达 n 2 n^2 n2级别(如全为 k k k的情况)。而加值操作固定为 m m m次。那么考虑牺牲加值操作的复杂度,使得 b b b数组的区间加操作复杂度变为 O ( 1 ) O(1) O(1)。
可以将加值操作按 e d ed ed降序排序,倒序遍历 r = i r=i r=i的区间,每次将 e d ≥ i ed\geq i ed≥i的加值操作更新到数组中。而对于每次区间加 [ l , r ] [l,r] [l,r]的询问,就是查询中 s t ≤ l st\leq l st≤l的 ∑ s t i ≤ l w i \sum \limits_{st_i\leq l}w_i sti≤l∑wi。将数组分块,维护加值操作即可。
区间加操作显然可以转换为差分,最后答案求个前缀和即可。这样加值操作总共是 O ( m n ) O(m\sqrt n) O(mn)的,单个区间加操作是 O ( 1 ) O(1) O(1)的。
下面到了分类讨论环节:
为保证复杂度,将区间加右端点为 r r r对应的可行 l l l个数 ≥ n \geq \sqrt n ≥n和 < n <\sqrt n <n的情况分别处理。
已经将所有 t l , t r t_l,t_r tl,tr相同且出现次数 ≥ n \geq\sqrt n ≥n的集合提取出来了,现在逐个集合进行处理。
将加值操作拆成 ( s t − 1 , − w ) , ( e d , w ) (st-1,-w),(ed,w) (st−1,−w),(ed,w),设后缀和为 S [ 5 ] S[5] S[5], S [ 5 ] [ p o s ] S[5][pos] S[5][pos]即为所有 l ≤ p o s ≤ r l\leq pos\leq r l≤pos≤r的区间的权值和。
设可行 l l l有 n l nl nl个,位置存在 q l ql ql数组中,可行 r r r有 n r nr nr个,位置存在 q r qr qr数组中。那么考虑对于一个区间加操作 [ l , r ] [l,r] [l,r]中 b l , b r + 1 b_l,b_{r+1} bl,br+1究竟加/减了哪些值。
需要维护6种前缀/后缀和,在这里先列出:
对于每个 b l b_l bl,加上 S [ 4 ] [ l ] S[4][l] S[4][l],但这样把 s t ≥ l , e d ≥ r st\geq l,ed\geq r st≥l,ed≥r的也加上了,所以减去 S [ 2 ] [ r ] S[2][r] S[2][r]。
对于每个 b r b_r br,减去 S [ 0 ] [ r ] × S [ 5 ] [ r ] S[0][r]\times S[5][r] S[0][r]×S[5][r],但同样把 s t ≥ l , e d ≥ r st\geq l,ed\geq r st≥l,ed≥r的也减去了,所以加上 S [ 3 ] [ r ] S[3][r] S[3][r]。
S [ 0 S[0 S[0~ 5 ] 5] 5]可以 O ( n + m ) O(n+m) O(n+m)处理出来,多了几遍循环,常数略大。
这样就做完了,代码实现如同上述。
p . s . p.s. p.s.按照 > n >\sqrt n >n判断会 T L E . . . TLE... TLE...,玄学调参设成 > 700 >700 >700就过了。
做这种题一定要有耐心,想清楚流程写在纸上以后再打代码。。。
#include
#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;
}