题目
首先用暴力的思想
就是遍历n然后二分跑tarjan l, m 找到合适的位置 插入进行 这个的复杂度为 n^2logn
所以考虑如何去优化
首先想到的就是倍增 毕竟logn算法也就他了
先用倍增找到合适的区间
复杂度是 nlogn (n为倍增的区间大小)
查找倍增区间里面的合适的范围 又为(nlogn)
所以总体范围即为 2*nlogn
#include<iostream>
#include<vector>
using namespace std;
const int N = 1e6 + 10,M = 1e6 + 10;
typedef long long ll;
int X[M],Y[M];
int n,m;
int dfn[N],low[N],times,sta[N],top,flag[N];
ll cur,k;
vector<int>v[N];
void tarjan(int x){
dfn[x] = low[x] = ++times;
sta[++top] = x,flag[x] = 1;
for(auto j : v[x]){
if(!dfn[j]){
tarjan(j);
low[x] = min(low[x],low[j]);
}else if(flag[j]){
low[x] = min(low[x],dfn[j]);
}
}
if(low[x] == dfn[x]){
int cnt = 0,s;
do{
s = sta[top--];
++cnt;
flag[s] = 0;
}while(s != x);
cur += 1ll * cnt * cnt;
}
}
bool check(int L,int R){
for(int i = L; i <= R; i++){
v[X[i]].push_back(Y[i]);
dfn[X[i]] = 0,dfn[Y[i]] = 0;
cur = n;
}
times = 0;
for(int i = L; i <= R; i++){
if(!dfn[X[i]]){
tarjan(X[i]);
}
}
cur -= times;
for(int i = L; i <= R; i++){
v[X[i]].clear();
}
return cur <= k;
}
int main(){
cin >> n >> m >> k;
for(int i = 1;i <= m; i++){
scanf("%d%d",&X[i],&Y[i]);
}
int ans = 0;
for(int i = 1; i <= m; i++){
int d = 0;
int l = i,r = i + (1 << d) - 1;
while(check(l,r)){
if(r > m) break;
d++;
r = i + (1 << d) - 1;
}
l = i + (1 << (d - 1)) - 1,r = min(m,r);
while(l < r){
int mid = l + r + 1 >> 1;
if(check(i,mid)){
l = mid;
}else r = mid - 1;
}
i = l,++ans;
}
cout << ans << endl;
return 0;
}