CCPC Final 2022 I 个人题解

link

令题目的操作为每次删连读段的第一个字符。考虑区间操作 \([l, r]\) 和前缀操作 \([1, r]\) 的区别,除了开头,后面部分是完全一致的,区间操作会额外从开头删一些。

考虑多删的那些是怎么来的,我们把操作变成删连续段的最后一个字符,不难发现应该删除的字符就落在 \([1, l-1]\) 的剩余字符中。

于是只需要模拟出每个位置的删除时间,做两个数点问题即可。

复杂度 \(O((n+q)\log n)\)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double dou;
typedef pair<int,int> pii;
#define fi first
#define se second
#define mapa make_pair
typedef long double ld;
typedef unsigned long long ull;
#define ep emplace_back
template <typename T>inline void read(T &x){
	x=0;char c=getchar();bool f=0;
	for(;c<'0'||c>'9';c=getchar()) f|=(c=='-');
	for(;c>='0'&&c<='9';c=getchar())
	x=(x<<1)+(x<<3)+(c^48);
	x=(f?-x:x);
}
const int N=1e6+5;
int T, n, m;
char s[N];
int tim[N];
vector<pii> add[N], del[N];
int ans[N];
int lp[N], rp[N];
int tr[N];
void mdf(int x){
	for(; x; x-=(x&-x)) ++tr[x];
}
int get(int x){
	int ret=0;
	for(; x<=n; x+=(x&-x)) ret+=tr[x];
	return ret;
}
void solve(){
	read(n); read(m);
	scanf("%s", s+1);
	for(int i=1, l, r, k; i<=m; ++i){
		read(l); read(r); read(k);
		add[r].ep(k, i);
		del[n-l+1].ep(k, i);
	}
	vector<int> vec;
	for(int i=1; i<=n; ++i) {
		lp[i]=i-1, rp[i]=i+1;
		if(s[i]!=s[i-1]) vec.ep(i);
	}
	int cur=0;
	while(!vec.empty()){
		++cur;
		vector<int> vec2;
		for(auto t:vec){
			vec2.ep(rp[t]);
			rp[lp[t]]=rp[t];
			lp[rp[t]]=lp[t];
			tim[t]=cur;
		}
		vec.clear();
		for(auto t:vec2){
			if(t<1||t>n) continue;
			if(tim[t]) continue;
			if(s[t]!=s[lp[t]]) vec.ep(t);
		}
	}
	for(int i=1; i<=n; ++i){
		mdf(tim[i]);
		for(auto t:add[i]){
			ans[t.se]+=get(t.fi+1);
		}
	}
	reverse(s+1, s+n+1);
	for(int i=1; i<=n; ++i) {
		lp[i]=i-1, rp[i]=i+1;
		tr[i]=0; tim[i]=0;
		if(s[i]!=s[i-1]) vec.ep(i);
	}
	cur=0;
	while(!vec.empty()){
		++cur;
		vector<int> vec2;
		for(auto t:vec){
			vec2.ep(rp[t]);
			rp[lp[t]]=rp[t];
			lp[rp[t]]=lp[t];
			tim[t]=cur;
		}
		vec.clear();
		for(auto t:vec2){
			if(t<1||t>n) continue;
			if(tim[t]) continue;
			if(s[t]!=s[lp[t]]) vec.ep(t);
		}
	}
	for(int i=n; i>=1; --i){
		for(auto t:del[i]){
			ans[t.se]-=get(t.fi+1);
		}
		mdf(tim[i]);
	}
	for(int i=1; i<=m; ++i){
		printf("%d\n", max(0, ans[i]));
	}
}
int main(){
	// freopen("D:\\nya\\acm\\A\\test.in","r",stdin);
	// freopen("D:\\nya\\acm\\A\\test.out","w",stdout);
	// read(T);
	T=1;
	while(T--){
		solve();
	}
	return 0;
}
posted @ 2025-07-27 17:43  Displace  阅读(10)  评论(1)    收藏  举报