牛客周赛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;
}