CF351D - Jeff and Removing Periods 题解
首先做一点显然的转化:在进行第一次操作之后,可以将相同的数排在一起,这样一次就能删掉一种数。如果一开始就能删光一种数的话,那么次数就是区间颜色数,否则就是区间颜色数 \(+1\)。
所以现在原问题变成了两个问题:求区间内不同颜色数,判断区间内是否有某种颜色满足其出现位置构成等差数列。
第一问是经典问题,可以离线后 BIT 做到 \(O(n\log n)\)。
考虑第二问,设 \(pre_i\) 表示 \(a_i\) 上一次出现的位置,\(nxt_i\) 表示 \(a_i\) 下一次出现的位置。\(pos_i\) 表示最小的左端点 \(l\),使得 \([l,i]\) 中 \(a_i\) 出现的位置成等差数列,\(a_l\) 不一定等于 \(a_r\)。显然前两项易求,\(pos\) 可以递推求出。
那么原问题相当于是检验 \(\max_{i=l}^{r}[pos_i\le l][nxt_i>r]\) 是否为 \(1\)。考虑离线扫描线,用线段树维护所有 \(nxt_i>r\) 的位置的 \(pos_i\) 最小值。扫到 \(r\) 的时候直接把 \(pre_r\) 位置的值设为 \(+\infty\),再更新 \(r\) 位置的值,最后判断 \([l,r]\) 的最小值是否 \(\le l\) 即可。
时间复杂度 \(O(n\log n)\)。
卡常:不难发现 \(nxt\) 数组是没用的,而且由于值域小,算 \(pre\) 的时候可以直接开桶。
这样就可以拿到最优解了。
Code:
#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#include<ext/pb_ds/hash_policy.hpp>
#define gt getchar
#define pt putchar
#define fst first
#define scd second
#define SZ(s) ((int)s.size())
#define all(s) s.begin(),s.end()
#define pb push_back
#define eb emplace_back
#define re register
typedef long long ll;
typedef double db;
typedef long double ld;
typedef unsigned long long ull;
typedef unsigned int uint;
const int N=1e5+5;
const int inf=1e9;
const int SIZE=(1<<14);
using namespace std;
using namespace __gnu_pbds;
typedef pair<int,int> pii;
template<class T,class I> inline void chkmax(T &a,I b){a=max(a,(T)b);}
template<class T,class I> inline void chkmin(T &a,I b){a=min(a,(T)b);}
inline bool __(char ch){return ch>=48&&ch<=57;}
inline char gc(){
static char buf[SIZE],*begin=buf,*end=buf;
return begin==end&&(end=(begin=buf)+fread(buf,1,SIZE,stdin),begin==end)?EOF:*begin++;
}
template<class T> inline void read(T &x){
x=0;bool sgn=0;static char ch=gc();
while(!__(ch)&&ch!=EOF) sgn|=(ch=='-'),ch=gc();
while(__(ch)) x=(x<<1)+(x<<3)+(ch&15),ch=gc();
if(sgn) x=-x;
}
template<class T,class ...I> inline void read(T &x,I &...x1){
read(x);
read(x1...);
}
template<class T> inline void print(T x){
static char stk[70];short top=0;
if(x<0) pt('-');
do{stk[++top]=x>=0?(x%10+48):(-(x%10)+48),x/=10;}while(x);
while(top) pt(stk[top--]);
}
template<class T> inline void printsp(T x){
print(x);
putchar(' ');
}
template<class T> inline void println(T x){
print(x);
putchar('\n');
}
int n,m,a[N],pre[N],pos[N],ans[N],mp[N];
vector<pair<pii,int> > vec[N];
vector<pii> qry[N];
int c[N];
inline int lowbit(int x){
return x&(-x);
}
inline void add(int x,int w){
while(x<=n){
c[x]+=w;
x+=lowbit(x);
}
}
inline int query(int x){
int ans=0;
while(x){
ans+=c[x];
x-=lowbit(x);
}
return ans;
}
struct Node{
int l,r;
int mn;
}node[N<<2];
inline int lson(int x){
return x<<1;
}
inline int rson(int x){
return x<<1|1;
}
inline void push_up(int p){
node[p].mn=min(node[lson(p)].mn,node[rson(p)].mn);
}
void build(int p,int l,int r){
node[p].l=l,node[p].r=r;
node[p].mn=inf;
if(l==r) return;
int mid=l+((r-l)>>1);
build(lson(p),l,mid);
build(rson(p),mid+1,r);
}
void update(int p,int x,int w){
int l=node[p].l,r=node[p].r;
if(l==r) return node[p].mn=w,void();
int mid=l+((r-l)>>1);
if(x<=mid) update(lson(p),x,w);
else update(rson(p),x,w);
push_up(p);
}
int query(int p,int ql,int qr){
int l=node[p].l,r=node[p].r;
if(ql<=l&&r<=qr) return node[p].mn;
int mid=l+((r-l)>>1),ans=inf;
if(ql<=mid) chkmin(ans,query(lson(p),ql,qr));
if(qr>mid) chkmin(ans,query(rson(p),ql,qr));
return ans;
}
signed main(){
read(n);
for(re int i=1;i<=n;++i){
read(a[i]);
pre[i]=mp[a[i]];
mp[a[i]]=i;
}
for(re int i=1;i<=n;++i){
if(!pre[i]) pos[i]=1;
else if(i-pre[i]==pre[i]-pre[pre[i]]) pos[i]=pos[pre[i]];
else pos[i]=pre[pre[i]]+1;
}
read(m);
for(re int l,r,i=1;i<=m;++i){
read(l,r);
vec[l-1].eb(make_pair(pii(l,i),-1));
vec[r].eb(make_pair(pii(l,i),1));
qry[r].eb(l,i);
}
for(re int r=1;r<=n;++r){
add(pre[r]+1,1);
for(auto qwq:vec[r]){
int l=qwq.fst.fst,id=qwq.fst.scd,w=qwq.scd;
ans[id]+=query(l)*w;
}
}
build(1,1,n);
for(re int r=1;r<=n;++r){
update(1,r,pos[r]);
if(pre[r]) update(1,pre[r],inf);
for(auto qwq:qry[r]){
int l=qwq.fst,id=qwq.scd;
ans[id]+=(query(1,l,r)>l);
}
}
for(re int i=1;i<=m;++i) println(ans[i]);
return 0;
}