UOJ637 数据结构 - 扫描线、线段树
题意
给定数列 \(\{a_n\}\),\(m\) 次询问若将 \(a_{l_i},a_{l_i+1},\dots,a_{r_i}\) 这些数 \(+1\),全局有多少个不同的数。询问相互独立。
题解
我是傻逼吧?
考虑一个数 \(x(1\le x\le \mathbf{n+1})\) 对哪些答案没有贡献。\(x\) 对 \([l,r]\) 没有贡献,当且仅当:
- \([1,l)\) 和 \((r,n]\) 中都没有 \(x\);
- \([l,r]\) 中没有 \(x-1\)。
相当于 \(\mathcal{O}(n)\) 次矩形加。扫描线直接做就好了。
如果没过,先把所有数组都开大试试。
代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
#define For(Ti,Ta,Tb) for(int Ti=(Ta);Ti<=(Tb);++Ti)
#define Dec(Ti,Ta,Tb) for(int Ti=(Ta);Ti>=(Tb);--Ti)
#define Debug(...) fprintf(stderr,__VA_ARGS__)
typedef long long ll;
const int N=1e6+5;
int n,m,a[N],ans[N];
struct Fenwick{
int t[N];
void Add(int p,int k){for(;p<=n;p+=p&-p) t[p]+=k;}
int Query(int p){int res=0;for(;p;p-=p&-p) res+=t[p]; return res;}
}bit;
struct Query{int i,l,r;} q[N];
struct Command{int p,l,r,w;} comm[N<<2];
int len=0;
void Update(int _ll,int lr,int rl,int rr){
if(_ll>lr||rl>rr) return;
comm[++len]={rl,_ll,lr,1},comm[++len]={rr+1,_ll,lr,-1};
}
vector<int> occ[N];
int main(){
#ifndef zyz
ios::sync_with_stdio(false),cin.tie(nullptr);
#endif
cin>>n>>m;
For(i,1,n) cin>>a[i],occ[a[i]].push_back(i);
For(i,1,m) cin>>q[i].l>>q[i].r,q[i].i=i;
sort(q+1,q+m+1,[](const Query &q1,const Query &q2){return q1.r<q2.r;});
For(i,1,n+1){
if(occ[i].empty()){
occ[i-1].insert(occ[i-1].begin(),0);
occ[i-1].push_back(n+1);
for(auto it=next(occ[i-1].begin());it!=occ[i-1].end();++it){
int l=*prev(it)+1,r=*it-1;
Update(l,r,l,r);
}
continue;
}
int l=occ[i].front(),r=occ[i].back(),L=1,R=n,br=0;
for(int p:occ[i-1]){
if(l<=p&&p<=r){br=1;break;}
if(p<l) L=max(L,p+1);
if(p>r) R=min(R,p-1);
}
if(!br) Update(L,l,r,R);
}
sort(comm+1,comm+len+1,[](const Command &c1,const Command &c2){return c1.p<c2.p;});
for(int i=1,j=1,k=1;i<=n;++i){
for(;k<=len&&comm[k].p==i;++k){
bit.Add(comm[k].l,comm[k].w),bit.Add(comm[k].r+1,-comm[k].w);
}
for(;j<=m&&q[j].r==i;++j) ans[q[j].i]=bit.Query(q[j].l);
}
For(i,1,m) cout<<n+1-ans[i]<<'\n';
return 0;
}
Written by Alan_Zhao