[Ynoi2016] 镜中的昆虫
题目描述
维护一个长为 \(n\) 的序列 \(a_i\),有 \(m\) 次操作。
-
将区间 \([l,r]\) 的值修改为 \(x\)。
-
询问区间 \([l,r]\) 出现了多少种不同的数,也就是说同一个数出现多次只算一个。
\(1\leq n , m \leq 10^5\),\(1\leq a_i\leq 10^9\)。
\(\rm 64MB.\)
题解
从题面上看,这是珂朵莉树的非随机加强版,直接上 ODT 肯定会爆,只能另寻他法。
为了计数不重不漏,强制令只有第一次出现的数才有贡献,反之则没有,即:位置 \(i\) 能向区间 \([l,r]\) 贡献当且仅当 \([l\leq i\leq r][pre_i\lt l]=1\),其中 \(pre_i\) 是 \(a_i\) 上次出现的位置,没有则为 \(0\)。
从限制的形式上看,这就是一个带修的二维数点,如果这题不卡空间的话,可以直接用树套树解决。但是它卡。
不妨把时间轴也看成一维,那么现在问题就变成三维偏序了,使用分治在 \(O(n\log^2 n)\) 的时间复杂度解决。
代码
#include<bits/stdc++.h>
using namespace std;
#define ssiz(x) (signed)x.size()
#define allc(x) x.begin(),x.end()
const int N=3e5+9;
int a[N],buc[N<<1],pre[N],n,m,tot;
int op[N],ql[N],qr[N],qx[N];
struct Seg{
int l,r,dat;
Seg(){}
Seg(int _l,int _r,int _d){l=_l,r=_r,dat=_d;}
bool operator <(const Seg x)const{return l<x.l;}
};
set<Seg> cs[N],s;
auto Split(int x){
auto it=s.lower_bound(Seg(x,x,0));
if(it!=s.end()&&it->l==x) return it;
--it;
int l=it->l,r=it->r,dat=it->dat;
cs[dat].erase(*it);
s.erase(it);
cs[dat].insert(Seg(l,x-1,dat));
cs[dat].insert(Seg(x,r,dat));
s.insert(Seg(l,x-1,dat));
return s.insert(Seg(x,r,dat)).first;
}
array<int,5> c[N<<2];
int p[N<<2],ans[N],tr[N];
void Add(int x,int k){
x++;
while(x<=n+1){
tr[x]+=k;
x+=x&-x;
}
}
int Ask(int x){
x++;
int sum=0;
while(x){
sum+=tr[x];
x&=x-1;
}
return sum;
}
void Solve(int l,int r){
if(l==r) return ;
int mid=l+r>>1;
Solve(l,mid),Solve(mid+1,r);
sort(p+l,p+mid+1,[](int x,int y){return c[x][1]<c[y][1];});
sort(p+mid+1,p+r+1,[](int x,int y){return c[x][1]<c[y][1];});
int i=l,j=mid+1;
while(j<=r){
while(i<=mid&&c[p[i]][1]<=c[p[j]][1]){
if(!c[p[i]][4]) Add(c[p[i]][2],c[p[i]][3]);
i++;
}
if(c[p[j]][4]) ans[c[p[j]][4]]+=Ask(c[p[j]][2])*c[p[j]][3];
j++;
}
while(--i>=l) if(!c[p[i]][4]) Add(c[p[i]][2],-c[p[i]][3]);
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
#define endl '\n'
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=m;i++){
cin>>op[i]>>ql[i]>>qr[i];
if(op[i]==1) cin>>qx[i];
}
vector<int> val;
for(int i=1;i<=n;i++) val.push_back(a[i]);
for(int i=1;i<=n;i++) if(op[i]==1) val.push_back(qx[i]);
val.push_back(-1);
sort(allc(val));
val.erase(unique(allc(val)),val.end());
for(int i=1;i<=n;i++) a[i]=lower_bound(allc(val),a[i])-val.begin();
for(int i=1;i<=m;i++) if(op[i]==1) qx[i]=lower_bound(allc(val),qx[i])-val.begin();
for(int i=1;i<=n;i++){
pre[i]=buc[a[i]],buc[a[i]]=i;
s.insert(Seg(i,i,a[i]));
cs[a[i]].insert(Seg(i,i,a[i]));
c[++tot]={0,pre[i],i,1,0};
}
for(int i=1;i<=m;i++){
if(op[i]==2){
c[++tot]={i,ql[i]-1,ql[i]-1,-1,i};
c[++tot]={i,ql[i]-1,qr[i],1,i};
continue ;
}
auto ri=Split(qr[i]+1),li=Split(ql[i]);
for(auto it=li;it!=ri;it++){
auto jt=cs[it->dat].upper_bound(*it);
if(jt==cs[it->dat].end()) continue ;
c[++tot]={i,pre[jt->l],jt->l,-1,0};
pre[jt->l]=pre[it->l];
c[++tot]={i,pre[jt->l],jt->l,1,0};
}
for(auto it=next(li);it!=ri;it++){
c[++tot]={i,pre[it->l],it->l,-1,0};
pre[it->l]=it->l-1;
c[++tot]={i,pre[it->l],it->l,1,0};
}
if(li->dat!=qx[i]){
auto it=cs[qx[i]].lower_bound(Seg(li->l,li->l,0));
c[++tot]={i,pre[li->l],li->l,-1,0};
if(it!=cs[qx[i]].begin()) pre[li->l]=(--it)->r;
else pre[li->l]=0;
c[++tot]={i,pre[li->l],li->l,1,0};
}
for(auto it=li;it!=ri;it++) cs[it->dat].erase(*it);
s.erase(li,ri);
cs[qx[i]].insert(Seg(ql[i],qr[i],qx[i]));
s.insert(Seg(ql[i],qr[i],qx[i]));
auto tmp=next(cs[qx[i]].lower_bound(Seg(ql[i],qr[i],qx[i])));
if(tmp!=cs[qx[i]].end()){
c[++tot]={i,pre[tmp->l],tmp->l,-1,0};
pre[tmp->l]=qr[i];
c[++tot]={i,pre[tmp->l],tmp->l,1,0};
}
}
iota(p+1,p+tot+1,1);
Solve(1,tot);
for(int i=1;i<=m;i++) if(op[i]==2) cout<<ans[i]<<endl;
return 0;
}

浙公网安备 33010602011771号