[DS记录]P4690 [Ynoi2016] 镜中的昆虫
command_block
2021-06-18 15:15:21
**题意** : 维护长度为 $n$ 的序列 $A$ ,支持 :
- 区间覆盖
- 区间数颜色
允许离线,$n,m\leq 10^5$ ,时限$\texttt{1.5s}$ ,空限$\texttt{64Mb}$。
------------
先离散化一手。
考虑区间数颜色的经典套路,维护 $pre_i$ 表示 $A_i$ 上一次出现的位置,然后区间 $[l,r]$ 的答案即为 :
$$\sum_{i=l}^r[pre_i<l]$$
这是二维数点。
考虑如何在区间覆盖的同时维护 $pre_i$ 。
使用 ODT 维护,会产生 $O(n+m)$ 次颜色连续段的修改。
每一个颜色连续段除了第一个位置之外,其余的 $pre_i$ 均为 $i-1$。分两部分维护。
第一部分是颜色连续段的第一个位置。我们除了用一个 `set` 维护连续段,还要用 $O(n+m)$ 个 `set` 维护每种颜色,这样才能 $O(\log n)$ 求一个 $pre$。
求答案时是动态二维偏序问题,容易转为静态三维偏序,然后用 $CDQ$ 分治解决。
对于其余 $pre_i=i-1$ 的点,只有 $pre_l$ 可能有贡献,单独判一下即可。
复杂度 $O\big((n+m)\log^2n\big)$ ,空间 $O(n+m)$。
> 不要访问删除过的迭代器!!!调了 $7$ 小时!!!
```cpp
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<set>
#define Pr pair<int,int>
#define fir first
#define sec second
#define mp make_pair
#define Itor set<Pr>::iterator
#define itor set<int>::iterator
#define MaxN 100500
using namespace std;
const int INF=1000000000;
int n;
#define lbit(x) (x&-x)
struct SumDS{
int t[MaxN<<1];
void add(int p,int c)
{p++;while(p<=n+1){t[p]+=c;p+=lbit(p);}}
void clr(int p)
{p++;while(p<=n+1){t[p]=0;p+=lbit(p);}}
int qry(int p){
int ret=0;p++;
while(p){ret+=t[p];p^=lbit(p);}
return ret;
}
}T;
struct Data{bool op;int x,y,p;}s[MaxN*10],st1[MaxN*5],st2[MaxN*5];
int ans[MaxN],tn;
void solve(int l,int r)
{
if (l==r)return ;
int mid=(l+r)>>1,lenl=mid-l+1,lenr=r-mid,tn=l-1;
solve(l,mid);solve(mid+1,r);
memcpy(st1,s+l,sizeof(Data)*lenl);
memcpy(st2,s+mid+1,sizeof(Data)*lenr);
int p=0;
for (int i=0;i<lenr;i++){
while(p<lenl&&st1[p].x<=st2[i].x){
if (st1[p].op==1)T.add(st1[p].y,st1[p].p);
s[++tn]=st1[p++];
}if (st2[i].op==0)ans[st2[i].p]+=T.qry(st2[i].y);
s[++tn]=st2[i];
}while(p<lenl)s[++tn]=st1[p++];
for (int i=0;i<lenl;i++)T.clr(st1[i].y);
}
set<int> tc[MaxN<<1];
set<Pr> sg;
int sp[MaxN];
void adp(int x,int y,int c)
{s[++tn]=(Data){1,x,y,c};T.add(max(x,y),c);}
void erase(Itor it){
int c=it->sec,p=it->fir;
itor pit=tc[c].lower_bound(p);pit++;
if (pit!=tc[c].end()){
Itor it=sg.lower_bound(mp(*pit,INF));
it--;pit--;pit--;
int p=it->fir;
adp(p,sp[p],-1);
adp(p,sp[p]=*pit,1);pit++;
}else pit--;
tc[c].erase(pit);
adp(p,sp[p],-1);sp[p]=-1;
sg.erase(it);
}
void insert(int l,int r,int c){
itor pit=tc[c].lower_bound(l);
if (pit!=tc[c].end()){
Itor it=sg.lower_bound(mp(*pit,INF));it--;
int p=it->fir;
adp(p,sp[p],-1);
adp(p,sp[p]=r,1);
}
adp(l,sp[l]=*(--pit),1);
sg.insert(mp(l,c));tc[c].insert(r);
}
struct QData{int op,l,r,x;}b[MaxN];
Itor st[MaxN];
int m,tq,a[MaxN],tx,x[MaxN<<1];
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++){scanf("%d",&a[i]);x[++tx]=a[i];}
for (int i=1;i<=m;i++){
scanf("%d%d%d",&b[i].op,&b[i].l,&b[i].r);
if (b[i].op==1){scanf("%d",&b[i].x);x[++tx]=b[i].x;}
}
sort(x+1,x+tx+1);tx=unique(x+1,x+tx+1)-x-1;
for (int i=1;i<=tx;i++)tc[i].insert(0);
sg.insert(mp(n+1,0));
for (int i=1;i<=n;i++){
int sav=lower_bound(x+1,x+tx+1,a[i])-x;
sg.insert(mp(i,sav));tc[sav].insert(i);
adp(i,sp[i]=*(--tc[sav].find(i)),1);
}
for (int i=1;i<=m;i++){
int l=b[i].l,r=b[i].r;
if (b[i].op==1){
Itor it=sg.lower_bound(mp(l,INF));
int nxt=it->fir;it--;
if (r<nxt){
Pr now=*it;erase(it);
if (now.fir<l)insert(now.fir,l-1,now.sec);
if (r<nxt-1)insert(r+1,nxt-1,now.sec);
}else {
Pr sav=*it;int tn=0;
while(it->fir<=r){st[++tn]=it;it++;}
int las=st[tn]->sec; //不要访问删除过的迭代器
for (int k=1;k<=tn;k++)erase(st[k]);
if (sav.fir<l)insert(sav.fir,l-1,sav.sec);
if (r+1<it->fir)insert(r+1,it->fir-1,las);
}insert(l,r,lower_bound(x+1,x+tx+1,b[i].x)-x);
}else {
ans[++tq]=(sp[b[i].l]==-1)-T.qry(b[i].l-1);
s[++tn]=(Data){0,b[i].r,b[i].l-1,tq};
}
}
memset(T.t,0,sizeof(T.t));
solve(1,tn);
for (int i=1;i<=tq;i++)
printf("%d\n",ans[i]);
return 0;
}
```