CF #629 Div.3 E(LCA)F
E
题意:给定一棵n个点的树,问是否能找到一条路径,使k个点要么在路径上,要么距路径长度为1。
分析:LCA
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<iostream>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<sstream>
typedef long long LL;
const int INF = 0x3f3f3f3f;
using namespace std;
const int MAXN = 200000 + 10;
const int LOG_MAXN = 18;
const double eps = 1e-8;
int dcmp(double a, double b){
if(fabs(a - b) < eps) return 0;
return a < b ? -1 : 1;
}
vector<int> G[MAXN];
int depth[MAXN];
int parent[LOG_MAXN][MAXN];
int n, m;
vector<int> V;
void dfs(int v, int p, int d){
depth[v] = d;
parent[0][v] = p;
int len = G[v].size();
for(int i = 0; i < len; ++i){
if(G[v][i] != p){
dfs(G[v][i], v, d + 1);
}
}
}
void init(){
dfs(1, -1, 0);
for(int k = 0; k + 1 < LOG_MAXN; ++k){
for(int v = 1; v <= n; ++v){
if(parent[k][v] == -1) parent[k + 1][v] = -1;
else{
parent[k + 1][v] = parent[k][parent[k][v]];
}
}
}
}
bool cmp(const int &a, const int &b){
return depth[a] < depth[b];
}
int lca(int u, int v){
if(depth[u] > depth[v]){
swap(u, v);
}
for(int k = 0; k < LOG_MAXN; ++k){
if((depth[u] - depth[v]) >> k & 1){
v = parent[k][v];
}
}
if(u == v) return u;
for(int k = LOG_MAXN - 1; k >= 0; --k){
if(parent[k][u] != parent[k][v]){
u = parent[k][u];
v = parent[k][v];
}
}
return parent[0][u];
}
int main(){
scanf("%d%d", &n, &m);
int x, y;
for(int i = 0; i < n - 1; ++i){
scanf("%d%d", &x, &y);
G[x].push_back(y);
G[y].push_back(x);
}
init();
while(m--){
int k;
scanf("%d", &k);
V.clear();
while(k--){
scanf("%d", &x);
V.push_back(x);
}
sort(V.begin(), V.end(), cmp);
int len = V.size();
bool ok = true;
for(int i = 1; i < len; ++i){
int tmp = lca(V[i], V[i - 1]);
if(depth[V[i]] - depth[tmp] > 1 && depth[V[i - 1]] - depth[tmp] > 1){
ok = false;
break;
}
}
if(ok) printf("YES\n");
else printf("NO\n");
}
return 0;
}
F
题意:有n个点,允许进行两种操作:(1)将最小的数加1(2)将最大的数减一,问最少操作几次,可以得到k个相等的数。
分析:遍历枚举答案取最小值。可以只取左边,只取右边,两边都取。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<string>
#include<iostream>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
#include<sstream>
typedef long long LL;
const int INF = 0x3f3f3f3f;
using namespace std;
const int MAXN = 200000 + 10;
const double eps = 1e-8;
int dcmp(double a, double b){
if(fabs(a - b) < eps) return 0;
return a < b ? -1 : 1;
}
LL a[MAXN], pre[MAXN], suf[MAXN];
map<LL, LL> l, r;
int main(){
LL n, k;
scanf("%lld%lld", &n, &k);
for(LL i = 1; i <= n; ++i){
scanf("%lld", &a[i]);
}
sort(a + 1, a + n + 1);
for(LL i = 1; i <= n; ++i){
pre[i] = pre[i - 1] + a[i];
if(!l[a[i]]){
l[a[i]] = i;
}
}
for(LL i = n; i >= 1; --i){
suf[i] = suf[i + 1] + a[i];
if(!r[a[i]]) r[a[i]] = i;
}
LL ans = 1000000000000000;
for(LL i = 1; i <= n; ++i){
LL cnt = r[a[i]] - l[a[i]] + 1;
if(cnt >= k){
ans = 0;
break;
}
LL cost1, cost2;
cost1 = (a[i] - 1) * (i - 1) - pre[i - 1];
cost2 = suf[r[a[i]] + 1] - (a[i] + 1) * (n - r[a[i]]);
if(cnt + i - 1 >= k){
ans = min(ans, cost1 + k - cnt);
}
if(cnt + n - r[a[i]] >= k){
ans = min(ans, cost2 + k - cnt);
}
ans = min(ans, cost1 + cost2 + k - cnt);
i += cnt - 1;
}
printf("%lld\n", ans);
return 0;
}