考虑没有修改就是 HH 的项链,每个位置维护 \(pre_i\) 表示上一个相同数的位置,询问等价于 \(\sum_{i=l}^r [pre_i<l]\),拆成差分形式就是二维偏序可以直接扫描线解决。
单点修改也是简单的,多了修改,相当于多了一个时间维,三维偏序用 cdq 分治解决即可。
而区间修改,这题关键在于其实实际上修改的位置是 \(O(n+m)\) 量级的。
区间推平实际修改的位置是 \(O(L)\),其中 \(L\) 是连续段个数。而每次最多将两个连续段分裂,则分裂出的连续段数为 \(O(m)\),加上原本的 \(n\) 个位置最劣是 \(O(n+m)\) 的。
也就是说对于区间推平同色段数实际上是 \(O(n+m)\) 量级。
也就是说直接 ODT 可以得出每次实际修改的位置与对应的值,然后直接 cdq 分治即可,时间复杂度 \(O((n+m)\log^2 (n+m))\)。
可能有点卡空间啊,尽量别用 vector 或是 shrink_to_fit 清下空间就好了。
#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
#define fin(x) freopen(#x".in","r",stdin)
#define fout(x) freopen(#x".out","w",stdout)
#define fr(x) fin(x),fout(x);
#define Fr(x,y) fin(x),fout(y)
#define INPUT(_1,_2,FILE,...) FILE
#define IO(...) INPUT(__VA_ARGS__,Fr,fr)(__VA_ARGS__)
using namespace std;
using namespace __gnu_pbds;
#define mp make_pair
#define pii pair<int,int>
#define fi first
#define se second
#define pb push_back
#define cfast ios::sync_with_stdio(false);cin.tie(0),cout.tie(0)
#define ll long long
#define ull unsigned long long
#define intz(x,y) memset((x),(y),sizeof((x)))
char *p1,*p2,buf[100000];
#define nc() (p1==p2 && (p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++)
#define tup(x) array<int,(x)>
inline ll read(){ll x=0,f=1;char ch=nc();while(ch<48||ch>57){if(ch=='-')f=-1;ch=nc();}while(ch>=48&&ch<=57)x=x*10+ch-48,ch=nc();return x*f;
}
//void write(int x){cout<<x<<' ';}
//void write(pii x){cout<<"P("<<x.fi<<','<<x.se<<")\n";}
//void write(vector<auto>x){for(auto i:x)write(i);cout<<'\n';}
//void write(auto *a,int l,int r){for(int i=l;i<=r;i++)write(a[i]);cout<<'\n';}
inline ll lowbit(ll x){return x&-x;}
#define pcount(x) __builtin_popcount(x)
inline void cmx(ll &x,ll y){if(y>x)x=y;}
inline void cmn(ll &x,ll y){if(y<x)x=y;}
const int mod=998244353;
ll qp(ll x,int y){ll res=1;for(;y;x=x*x%mod,y>>=1)if(y&1)res=res*x%mod;return res;}
const int N=2e5+5,M=2e6+5;
int a[N],pre[N],lst[N],T,tot,t[N],n,m,ans[N],len;unordered_map<int,int>id;
struct opt{int x,y,v,id;}w[M];
struct odt{#define auto set<node>::iteratorstruct node{int l,r,x;friend bool operator<(node x,node y){return x.l<y.l;}};set<node>t,col[N];auto insert(int l,int r,int x){return col[x].insert(node{l,r}),t.insert({l,r,x}).fi;}void delet(int l,int r,int x){col[x].erase(node{l,r}),t.erase({l,r,x});}auto split(int x){auto it=t.lower_bound(node{x,0,0});if(it!=t.end()&&it->l==x)return it;--it;int l=it->l,r=it->r,v=it->x;delet(l,r,v),insert(l,x-1,v);return insert(x,r,v);}int p(int x){auto it=--t.upper_bound(node{x,0,0});if(it->l==x){auto i=col[it->x].lower_bound(node{x,0,0});return (i==col[it->x].begin()?0:(--i)->r);}else return x-1;}int q[N<<2],_;void upd(int l,int r,int x){auto itr=split(r+1),itl=split(l);_=0;for(auto it=itl;it!=itr;it++){q[++_]=(it->l);auto nxt=col[it->x].upper_bound(*it);if(nxt!=col[it->x].end())q[++_]=(nxt->l);col[it->x].erase(*it);}t.erase(itl,itr),insert(l,r,x);auto nxt=col[x].upper_bound(node{l,r,x});if(nxt!=col[x].end())q[++_]=(nxt->l);for(int I=1,i;I<=_;I++)i=q[I],w[++len]={i,pre[i],-1,0},pre[i]=p(i),w[++len]={i,pre[i],1,0};}#undef auto
}ot;
#define b(x) (x).begin()
inline void upd(int x,int d){++x;for(;x<=n;x+=lowbit(x))t[x]+=d;}
inline int ask(int x){int res=0;++x;for(;x;x-=lowbit(x))res+=t[x];return res;}
inline void clr(int x){++x;for(;x<=n;x+=lowbit(x))t[x]=0;}
bool cmp(opt x,opt y){return x.x<y.x;}
void cdq(int L,int R){if(L==R)return;int mid=L+R>>1;cdq(L,mid),cdq(mid+1,R);for(int l=L,r=mid+1;r<=R;r++){while(l<=mid&&w[l].x<=w[r].x)(w[l].id?0:(upd(w[l].y,w[l].v),1)),++l;if(w[r].id)ans[w[r].id]+=w[r].v*ask(w[r].y);}for(int i=L;i<=mid;i++)if(!w[i].id)clr(w[i].y);inplace_merge(w+L,w+1+mid,w+1+R,cmp);
}
inline void UesugiErii(){cin>>n>>m;for(int i=1,x;i<=n;i++){cin>>x;if(id.find(x)==id.end())id[x]=++T;a[i]=id[x];pre[i]=lst[a[i]],lst[a[i]]=i,w[++len]={i,pre[i],1,0},ot.insert(i,i,a[i]);}for(int i=1;i<=m;i++){int op,l,r,x;cin>>op>>l>>r;if(op==1){cin>>x;if(id.find(x)==id.end())id[x]=++T;x=id[x];ot.upd(l,r,x);}else ++tot,w[++len]={l-1,l-1,-1,tot},w[++len]={r,l-1,1,tot};}cdq(1,len);for(int i=1;i<=tot;i++)cout<<ans[i]<<'\n';
}
signed main(){//IO();cfast;int _=1;//cin>>_;for(;_;_--)UesugiErii();return 0;
}