题目链接:https://codeforces.com/contest/1847/problem/D
思路:对于同一个位置,后出现的是无意义的,所以只需要找到每个位置第一次出现的次序,暴力写是的,可以转化为区间覆盖模型,这是并查集的一个经典应用。对于询问,先统计原字符串中1的个数cnt,最小操作数ans。然后对于每个询问动态维护cnt,ans,s的值即可。
注意:并查集初始话一定要到p[n+1],不然在导致MLE
Code
//并查集
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define PII pair<int,int>
#define endl "\n"
typedef long long LL;
const int N=2e5+10;
int p[N];
int pos[N];
int find(int x) {
if(p[x]!=x) p[x]=find(p[x]);
return p[x];
}
void solve() {
int n,m,q;
string s;
cin>>n>>m>>q>>s;
s='?'+s;
for(int i=1;i<=n+1;i++) p[i]=i,pos[i]=-1; //p[n+1]也要初始化
vector<int> v;
int _idx=0;
while(m--) {
int l,r;
cin>>l>>r;
for(int i=find(l);i<=r;i=find(i)) {
v.push_back(i);
pos[i]=++_idx;
p[i]=i+1;
}
}
int cnt=0;
for(int i=1;i<=n;i++) {
cnt+=(s[i]=='1');
}
int ans=0;
for(int i=0;i<min(cnt,(int)v.size());i++) {
ans+=(s[v[i]]=='0');
}
while(q--) {
int idx;
cin>>idx;
if(pos[idx]!=-1&&pos[idx]<=cnt) {
if(s[idx]=='0') ans--;
else ans++;
}
if(s[idx]=='0') {
s[idx]='1';
cnt++;
if(cnt<=(int)v.size()&&s[v[cnt-1]]=='0') ans++;
}
else {
s[idx]='0';
if(cnt<=(int)v.size()&&s[v[cnt-1]]=='0') ans--;
cnt--;
}
cout<<ans<<endl;
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cout.tie(nullptr);
solve();
return 0;
}
这里我vector越界了,然后TLE了,奇怪的TLE原因增加了