A :传送门:​​点我​

求联通块个数,对于简单图而言,就是c=v-e,其中c就是联通块个数,v是顶点数,e是边数

#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>

using namespace std;
const int MAX_N = 2e5 + 10;
int N, M, K;

vector<int> G[MAX_N];
int vis[MAX_N];
int degree[MAX_N];

void dfs(int v, int p) {
vis[v] = 1;
for (int i = 0; i < G[v].size(); i++) {
int u = G[v][i];
if (!vis[u] && u != p)
dfs(u, v);
}
}

int main() {
int T;
scanf("%d", &T);
while (T--) {
scanf("%d %d %d", &N, &M, &K);
for (int i = 0; i < N; i++) {
G[i].clear();
vis[i] = 0;
degree[i] = 0;
}

int a, b;
for (int i = 0; i < M; i++) {
scanf("%d %d", &a, &b);
G[a].push_back(b);
G[b].push_back(a);
degree[a]++;
degree[b]++;
}

int cnt = 0;
for (int i = 0; i < N; i++)
if (!vis[i]) {
cnt++;
dfs(i, -1);
}
int ans = 0;
for (int i = 0; i < N; i++) {
int tmp = N - degree[i] - 1;
int t = min(tmp, cnt - 1 + K);
ans = max(ans, degree[i] + t);
}
printf("%d\n", ans);
}
return 0;
}

D p1m2 传送门:​​点我​

二分答案,会超时,加一个前缀

#include <algorithm>
#include <cstdio>
using namespace std;
const int MAX_N = 3e5 + 10;
typedef long long ll;
int X[MAX_N];
int N;
ll sum[MAX_N];
bool cmp(int a,int b){
return a>b;
}

int check(int x){
int i;
ll cnt=0;
for (i = 1; i <= N; i++){
if (X[i] > x)
cnt += (X[i]-x)/2; //减的次数
else
break;
/* if (X[i] > x) {
int t = (X[i] - x) / 2;
cnt -= t;
}*/
}
cnt=cnt-((ll)(N-i+1)*x-sum[i]);
if(cnt>0){
return 1;
}
else if(cnt==0){
return 0;
}
else return -1;
}
int main(){
int T;
scanf("%d", &T);
while (T--) {
scanf("%d", &N);
int l = 1e8, r = 0;
for (int i = 1; i <= N; i++){
scanf("%d", &X[i]);
l=min(l,X[i]);r=max(r,X[i]);
}
sort(X+1,X+N+1,cmp);//求一个后缀和
sum[N]=X[N];
for(int i=N-1;i>=1;i--){

sum[i]=sum[i+1]+X[i];
}
int ans=-1;
while (l <= r) {
int mid = l + r >> 1;
int j = check(mid);
if (j >= 0){
ans=mid;
l = mid+1;
}

else
r = mid-1;
}
printf("%d\n", ans);
}
return 0;
}