专栏文章
?
P6019题解参与者 3已保存评论 2
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 2 条
- 当前快照
- 1 份
- 快照标识符
- @mip6q2t6
- 此快照首次捕获于
- 2025/12/03 07:04 3 个月前
- 此快照最后确认于
- 2025/12/03 07:04 3 个月前
给一种没什么细节的做法。
静态版本就是 P1494,那么此题考虑根号算法。
单点修改是 CF2043G,考虑直接分块。
考虑把贡献统计到后加入的点上(后操作),维护整块之间两两的贡献,设 表示点对 一个在 块,后加入的点在第 块, 同理,散点暴力加入,那么还需记录 表示前 块 出现的次数,来 得到区间块内一个值的出现次数,统计答案和单点修改时都可以做到 。
推广到区间推平,考虑套上颜色段均摊,发现一个整个块都是一个颜色的时候复杂度爆了,这种情况不加入贡献最后类似散块加入即可。
默认 同阶,复杂度 ,不是很难写。
具体细节可以看代码理解:
CPP#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb push_back
const int N=2e5+3,B=444,M=N/B+3;
int n,m,tot,a[N],bel[N],Bl[N],Br[N],Len[N],cnt[N],tag[N];
int sl[M][M],sr[M][M],pre[N][M];
struct Seg{int l,r,v;};
#define Info vector<Seg>
Info S[M];
vector<int>del;
inline int Get(int l,int r,int v){return pre[v][r]-pre[v][l-1];}
inline int C2(int x){return x*(x-1)/2;}
#define len (r-l+1)
void Add(int l,int r,int v)
{
int id=bel[l],w=C2(len);
for(int p=id;p;p--)sl[p][id]+=Get(p,id,v)*len+w;
for(int p=id+1;p<=tot;p++)sr[p][id]+=Get(id+1,p,v)*len;
for(int p=id;p<=tot;p++)pre[v][p]+=len;
}
void Del(int l,int r,int v)
{
int id=bel[l],w=C2(len);
for(int p=id;p<=tot;p++)pre[v][p]-=len;
for(int p=id+1;p<=tot;p++)sr[p][id]-=Get(id+1,p,v)*len;
for(int p=id;p;p--)sl[p][id]-=Get(p,id,v)*len+w;
}
ll Ans(ll l,ll r)
{
return accumulate(sl[l]+l,sl[l]+r+1,0ll)+accumulate(sr[r]+l,sr[r]+r+1,0ll);
}
array<Info,3> Split(int id,int L,int R)
{
Info kl,o,kr;
for(auto [l,r,v]:S[id])
{
int ql=max(l,L),qr=min(r,R),wr=min(r,L-1),wl=max(l,R+1);
if(ql<=qr)o.pb({ql,qr,v});
if(l<=wr)kl.pb({l,wr,v});
if(wl<=r)kr.pb({wl,r,v});
}
return {kl,o,kr};
}
Info Merge(Info A,Info B,Info C)
{
Info D=A;
for(auto t:B)D.pb(t);
for(auto t:C)D.pb(t);
return D;
}
void Mdf(int L,int R,int d)
{
int id=bel[L];
if(tag[id])Add(Bl[id],Br[id],tag[id]),tag[id]=0;
auto [kl,o,kr]=Split(id,L,R);
for(auto [l,r,v]:o)Del(l,r,v);
if(kl.size()||kr.size())Add(L,R,d);
else tag[id]=d;
S[id]=Merge(kl,{{L,R,d}},kr);
}
void Upd(int l,int r,int d)
{
int bl=bel[l],br=bel[r];
if(bl==br)return Mdf(l,r,d);
Mdf(l,Br[bl],d);Mdf(Bl[br],r,d);
for(int i=bl+1;i<br;i++)
if(tag[i])S[i][0].v=tag[i]=d;
else Mdf(Bl[i],Br[i],d);
}
ll Ask(int L,int R)
{
while(del.size())cnt[del.back()]=0,del.pop_back();
ll bl=bel[L],br=bel[R],s=0;
if(bl==br)
{
auto [kl,o,kr]=Split(bl,L,R);
for(auto [l,r,v]:o)s+=cnt[v]*len+C2(len),cnt[v]+=len,del.pb(v);
return s;
}
s=Ans(bl+1,br-1);
auto [_l1,o1,_r1]=Split(bl,L,Br[bl]);
auto [_lr,o2,_r2]=Split(br,Bl[br],R);
for(auto [l,r,v]:o1)s+=cnt[v]*len+C2(len),s+=len*Get(bl+1,br-1,v),cnt[v]+=len,del.pb(v);
for(auto [l,r,v]:o2)s+=cnt[v]*len+C2(len),s+=len*Get(bl+1,br-1,v),cnt[v]+=len,del.pb(v);
for(int i=bl+1;i<br;i++)if(tag[i])
s+=cnt[tag[i]]*Len[i]+C2(Len[i]),s+=Len[i]*Get(bl+1,br-1,tag[i]),cnt[tag[i]]+=Len[i],del.pb(tag[i]);
return s;
}
int main()
{
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>m;tot=(n-1)/B+1;
for(int i=1;i<=n;i++)cin>>a[i],bel[i]=(i-1)/B+1;
for(int i=1;i<=tot;i++)Bl[i]=Br[i-1]+1,Br[i]=min(i*B,n),Len[i]=Br[i]-Bl[i]+1;
for(int i=1;i<=n;i++)Add(i,i,a[i]),S[bel[i]].pb({i,i,a[i]});
for(ll t=1,ans=0,op,l,r,d;t<=m;t++)
{
cin>>op>>l>>r;unsigned las=ans;
l^=las;r^=las;
if(op==1)cin>>d,Upd(l,r,d^las);
else cout<<(ans=Ask(l,r))<<"\n";
}
}
相关推荐
评论
共 2 条评论,欢迎与作者交流。
正在加载评论...