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;
}
posted @ 2024-02-28 15:03  Southern_Dynasty  阅读(2)  评论(0编辑  收藏  举报