牛客周赛39F 小红不想做模拟题
考虑暴力做法,即
n
2
n^2
n2,这样肯定超时,那么我们考虑如何进行优化,我们猜想是否可以不用每次都对整个子段进行遍历,我们是否可能只遍历其中的一部分,具体是什么部分,对于一段连续的一,我们可以记录其起点能到达的最远点,那么当我们遍历到这个起点时,我们可以直接跳到那个最远的点去,对于序列中的其他点都同理,那么考虑修改,对于当前为
0
0
0 的点,把他修改成
1
1
1 ,那么其最远点也就从当前的位置
i
i
i 变为了
i
+
1
i+1
i+1。这就是链式并查集。
#include <bits/stdc++.h>
using namespace std;
const int N = 5e5 + 5;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef array<int, 3> ar;
int mod = 1e9+7;
// const int maxv = 4e6 + 5;
// #define endl "\n"
int p[N][2];
int find(int x,int pos)
{
if(p[x][pos]!=x) return p[x][pos]=find(p[x][pos],pos);
return p[x][pos];
}
void solve()
{
int n;
cin>>n;
string a,b;
cin>>a>>b;
a=" "+a,b=" "+b;
for(int i=1;i<=n+1;i++){
p[i][0]=i,p[i][1]=i;
}
int ans=0;
for(int i=1;i<=n;i++){
if(a[i]=='1'&&b[i]=='1') ans++;
if(a[i]=='1') p[i][0]=i+1;
if(b[i]=='1') p[i][1]=i+1;
}
int q;
cin>>q;
while(q--){
char c;
int l,r;
cin>>c>>l>>r;
if(c=='A'){
l=find(l,0);
while(l<=r){
if(find(l,1)!=l) ans++;
p[l][0]=l+1;
l=find(l,0);
}
}
else{
l=find(l,1);
while(l<=r){
if(find(l,0)!=l) ans++;
p[l][1]=l+1;
l=find(l,1);
}
}
cout<<ans<<endl;
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
t=1;
// cin>>t;
while(t--){
solve();
}
system("pause");
return 0;
}
对于此题同理,我们每次学习后,都将当前点指向下一个点即可,我们跳了多少次,就是有多少个新知识点。
#include <bits/stdc++.h>
using namespace std;
const int N = 2e6 + 5;
typedef long long ll;
typedef pair<ll, ll> pll;
typedef array<ll, 3> p3;
int mod = 1e9+7;
const int maxv = 4e6 + 5;
#define endl '\n'
int p[N];
int find(int x)
{
if(p[x]!=x) return p[x]=find(p[x]);
return p[x];
}
void solve()
{
int n,m;
cin>>n>>m;
for(int i=1;i<=n+5;i++) p[i]=i;
while(m--){
int l,r;
cin>>l>>r;
int cnt=0;
for(int i=find(l);i<=r;i=find(i+1)){
cnt++;
p[i]=find(r+1);
}
cout<<cnt<<endl;
}
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
t=1;
//cin>>t;
while(t--){
solve();
}
//system("pause");
return 0;
}