Round #670 Div. 2

1406C - Link Cut Centroids

结论:树有一个或两个重心,如果有两个重心,那么它们一定直接相连。

那就好说了,如果只有一个重心,随便断一条边连上;如果有两个,设为 c e n t 1 cent_1 cent1 c e n t 2 cent_2 cent2,那么找到 c e n t 2 cent_2 cent2所在子树上摘一个叶子连到 c e n t 1 cent_1 cent1上。

#include <bits/stdc++.h>
using namespace std;
#define rep(i, a, b) for (int i = a; i < b; ++i)
const int N = 100010;
int n, sz[N], fa[N], minn = 1e9, cent1, cent2;
vector<int> g[N];
int S;
void dfs(int x, int f) {
  fa[x] = f, sz[x] = 1;
  int mx = 0;
  for (int y : g[x]) {
    if (y == f) continue;
    dfs(y, x);
    sz[x] += sz[y];
    mx = max(mx, sz[y]);
  }
  mx = max(mx, n - sz[x]);
  if (mx < minn)
    minn = mx, cent1 = x, cent2 = 0;
  else if (mx == minn)
    cent2 = x;
}
void dfs2(int x, int f) {
  if (g[x].size() == 1) {
    S = x;
    return;
  }
  for (int y : g[x]) {
    if (y == f) continue;
    dfs2(y, x);
  }
}
int main() {
  int tc;
  cin >> tc;
  while (tc--) {
    cin >> n;
    cent1 = cent2 = 0, minn = 1e9;
    rep(i, 1, n + 1) g[i].clear(), fa[i] = 0;
    rep(i, 1, n) {
      int u, v;
      cin >> u >> v;
      g[u].push_back(v);
      g[v].push_back(u);
    }
    dfs(1, 0);
    if (!cent2) {
      printf("1 %d\n1 %d\n", g[1][0], g[1][0]);
      continue;
    }
    if (fa[cent1] != cent2) swap(cent1, cent2);
    dfs2(cent1, cent2);
    printf("%d %d\n%d %d\n", S, fa[S], S, cent2);
  }
}

1406D - Three Sequences

给定数组 a a a,需要寻找两个数组 b , c b, c b,c,使得

  1. b 1 + c i = a i b_1 + c_i = a_i b1+ci=ai
  2. b b b单调不下降
  3. c c c单调不上升

需要最小化 max ⁡ ( b i , c i ) \max(b_i, c_i) max(bi,ci)

之后还会有 q q q个改变,每次给出三个整数 l , r , x l, r, x l,r,x,将 a a a数组中 [ l , r ] [l, r] [l,r]之间的数字增加 x x x

经过简单的推导之后发现只需要最小化 max ⁡ ( b n , c 1 ) \max(b_n, c_1) max(bn,c1)即可。

可以发现
{ { b i = b i − 1 + a i − a i − 1 c i = c i − 1 if a i > a i − 1 { b i = b i − 1 c i = c i − 1 + a i − a i − 1 if a i < a i − 1 \begin{cases} \left \{ \begin{aligned} b_i &= b_{i-1}+a_i-a_{i-1} \\ c_i &= c_{i-1} \end{aligned} \right. & \text{if}\quad a_i > a_{i-1} \\ \left \{ \begin{aligned} b_i &= b_{i-1} \\ c_i &= c_{i-1}+a_i-a_{i-1} \end{aligned} \right. & \text{if}\quad a_i < a_{i-1} \\ \end{cases} {bici=bi1+aiai1=ci1{bici=bi1=ci1+aiai1ifai>ai1ifai<ai1
K = ∑ i = 2 n max ⁡ ( 0 , a i − a i − 1 ) K = \sum\limits_{i=2}^{n}\max(0,a_i-a_{i-1}) K=i=2nmax(0,aiai1),设 c 1 = x c_1 = x c1=x,则 b 1 = a 1 − x b_1 = a_1 - x b1=a1x b n = b 1 + K = a 1 − x + K b_n = b_1 + K = a_1 - x + K bn=b1+K=a1x+K

需要最小化 max ⁡ ( x , a 1 − x + K ) \max(x, a_1-x+K) max(x,a1x+K),初始 x x x应设置为 a 1 + K 2 \dfrac{a_1 + K}{2} 2a1+K。注意当 a 1 + K a_1+K a1+K是奇数时, ∣ c 1 − b n ∣ = 1 |c_1 - b_n| = 1 c1bn=1,也就是一个会比另一个大出 1 1 1

接下来的 q q q次询问只会改变 ∑ max ⁡ ( 0 , a i − a i − 1 ) \sum\max(0,a_i-a_{i-1}) max(0,aiai1),所以只有 a l − a l − 1 a_l - a_{l-1} alal1 a r + 1 − a r a_{r+1}-a_r ar+1ar需要改变。注意当 l = 1 l=1 l=1 a 1 a_1 a1也要进行改变。

每次输出 max ⁡ ( x , a 1 − x + K ) \max(x, a_1-x+K) max(x,a1x+K)即可。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值