专栏文章

P6019题解参与者 3已保存评论 2

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
2 条
当前快照
1 份
快照标识符
@mip6q2t6
此快照首次捕获于
2025/12/03 07:04
3 个月前
此快照最后确认于
2025/12/03 07:04
3 个月前
查看原文
给一种没什么细节的做法。
静态版本就是 P1494,那么此题考虑根号算法。
单点修改是 CF2043G,考虑直接分块。
考虑把贡献统计到后加入的点上(后操作),维护整块之间两两的贡献,设 sli,jsl_{i,j} 表示点对 (x,y)(x,y) 一个在 [i,j][i,j] 块,后加入的点在第 jj 块,sri,jsr_{i,j} 同理,散点暴力加入,那么还需记录 prev,ipre_{v,i} 表示前 iivv 出现的次数,来 O(1)O(1) 得到区间块内一个值的出现次数,统计答案和单点修改时都可以做到 O(n)O(\sqrt n)
推广到区间推平,考虑套上颜色段均摊,发现一个整个块都是一个颜色的时候复杂度爆了,这种情况不加入贡献最后类似散块加入即可。
默认 n,mn,m 同阶,复杂度 O(nn)O(n\sqrt n),不是很难写。
具体细节可以看代码理解:
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 条评论,欢迎与作者交流。

正在加载评论...