Codeforces Round #629(div3)題解

比賽鏈接

D
題意:
給你n個數(形成一個換),現在要讓你給這n個數上色,只有一個限制:如果相鄰的兩個數不同,那他們倆的的顏色也要不同。
現在問你最少需要顏色的數量,然後輸出結果。

思路:
感覺沒幾種情況,分類討論一下就過了。
1.如果所有數都相等只要一種顏色。
2.如果長度n爲偶數的話,只要兩種顏色,1 2 1 2…這樣排就完事了。
那我們接下來是要考慮n爲奇數的情況。
現在假設n個數的編號爲1~n, 每個數爲t[i] (1<= i <= n)
1.如果t[i] == t[n], 那這個限制條件就跟他沒有關係,1 2 1 2…這樣排就完事。
2.如果t[i] != t[n-1], 如果我們還是像之前那麼1 2 1 2的排就有問題了,因爲長度爲奇數,最後一個數的顏色是1, 第一個數的顏色也是1(因爲是個環嘛,所以他們兩個相鄰), 而他們兩個數不同,而我們唯一要做的就是讓相鄰兩個數,如果數不同的話染的顏色也要不同,那我就想可不可以讓中間有一個11或者22的,這樣第一個和最後一個數的顏色就不同了, 那麼能變成11或者22的唯一條件就是兩個數相同,然後就沒了。
比賽寫的代碼太醜了就不放了 :>

E
題意:
給一個數,然後告訴你k個點,問你能不能找出一條鏈,這k個點要麼在這條鏈上,要麼和這條鏈距離爲1。

思路:
原來dfs序還能這麼用,學到了,之前dfs序只用來搞過線段樹, 現在知道dfs序還能判斷一個點在不在另一個點的子數上(其實本來就是有那層含義,但dfs序放在線段樹的題裏是要找出一個點子樹上的所有點)。
先找到最深的那個點,然後把給的除了那個點的其他點都變成他的父親節點,然後看這些點在不在一條鏈上,注意這兩者的順序不能顛倒,這裏給個例子:
三條邊 (1, 2) (1, 3)(1, 4), 問你點2,3,4符不符合條件。

dfs序:

/**
* Think twice, code once.
* 1.integer overflow(maybe even long long overflow : (a+b >= c) -> (a >= c-b)
* 2.runtime error
* 3.boundary condition
* ---------------------------------------------------------------------------------------
* Author : zzy
* Date : 2020-03-28-23.21.21 Saturday
*/
#include <bits/stdc++.h>

#define eb emplace_back
#define mp make_pair
#define mt make_tuple
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define forn(i, n) for (int i = 0; i < (int)(n); ++i)
#define for1(i, n) for (int i = 1; i <= (int)(n); ++i)
#define ford(i, a, b) for (int i = (int)(a); i >= (int)b; --i)
#define fore(i, a, b) for (int i = (int)(a); i <= (int)(b); ++i)
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define ms(x, y) memset(x, y, sizeof(x))
#define SZ(x) ((int)(x).size())

using namespace std;

typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector<vi> vvi;
typedef long long i64;
typedef vector<i64> vi64;
typedef vector<vi64> vvi64;
typedef pair<i64, i64> pi64;
typedef double ld;

template<class T> bool uin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool uax(T &a, T b) { return a < b ? (a = b, true) : false; }

const int maxn = 2*(int)1e5+1000;
int n, m, tot = 1, vis[maxn], in[maxn], out[maxn], pa[maxn], dep[maxn];
vvi g(maxn);

bool belong(int a, int b) {
    if (in[a] <= in[b] && in[b] <= out[a]) return true;
    return false;
}
void dfs(int u, int par) {
    in[u] = tot++;
    if (par) pa[u] = par;
    if (par) dep[u] = dep[par]+1;
    for (int to : g[u]) {
        if (to == par) continue;
        dfs(to, u);
    }
    out[u] = tot;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.precision(10);
    cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("input.txt", "r", stdin);
#endif

    cin >> n >> m;
    for1(i, n) pa[i] = i;
    forn(i, n-1) {
        int u, v;
        cin >> u >> v;
        g[u].eb(v);
        g[v].eb(u);
    }
    ms(vis, 0);
    ms(dep, 0);
    dfs(1, 0);
    forn(i, m) {
        bool ok = true;
        int k;
        cin >> k;
        vector< pair<int, int> > v(k);
        forn(i, k) {
            int x;
            cin >> x;
            v[i] = {dep[x], x};
        }
        sort(all(v));
        int leaf = v[k-1].se;
        for (int i = 0; i < k-1; ++i) {
            v[i].se = pa[v[i].se];
        }
        for (int i = 0; i < k-1; ++i) {
            if (!belong(v[i].se, leaf)) {
                ok = false;
                break;
            }
        }
        cout << (ok?"YES":"NO") << '\n';
    }

#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}

LCA:dfs+ST表寫法

/**
* Author : zzy
* Date : 2020-04-16-15.49.41 Thursday
*/
#include <bits/stdc++.h>

#define eb emplace_back
#define mp make_pair
#define mt make_tuple
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(), (x).end()
#define rall(x) (x).rbegin(), (x).rend()
#define forn(i, n) for (int i = 0; i < (int)(n); ++i)
#define for1(i, n) for (int i = 1; i <= (int)(n); ++i)
#define ford(i, a, b) for (int i = (int)(a); i >= (int)b; --i)
#define fore(i, a, b) for (int i = (int)(a); i <= (int)(b); ++i)
#define rep(i, l, r) for (int i = (l); i <= (r); i++)
#define per(i, r, l) for (int i = (r); i >= (l); i--)
#define ms(x, y) memset(x, y, sizeof(x))
#define SZ(x) ((int)(x).size())

using namespace std;

typedef pair<int, int> pii;
typedef vector<int> vi;
typedef vector<pii> vpi;
typedef vector<vi> vvi;
typedef long long i64;
typedef vector<i64> vi64;
typedef vector<vi64> vvi64;
typedef pair<i64, i64> pi64;
typedef double ld;

template<class T> bool uin(T &a, T b) { return a > b ? (a = b, true) : false; }
template<class T> bool uax(T &a, T b) { return a < b ? (a = b, true) : false; }

const int maxn = 4*(int)1e5+5; //歐拉序是兩倍的點數量的多少
int loc[maxn],num[maxn],dep[maxn],LOG[maxn];
int dp[25][maxn], point[25][maxn];          //2^20 == 1e6  2^25 == 3e7
int par[maxn], val[maxn];
int all = 0;
int head[maxn], tot=0;
struct Edge{
    int nxt, to, val;
}edge[maxn];
int tc, n, m;

int read() {
    int ans = 0, f = 1; char c = getchar();
    for (;c < '0' | c > '9'; c = getchar()) if (c == '-') f = -1;
    for (;c >= '0' && c <= '9'; c = getchar()) ans = ans * 10 + c - '0';
    return ans * f;
}
void addEdge(int x,int y) {
    edge[tot].to = y;
    edge[tot].nxt = head[x];
    head[x] = tot++;
}
void dfs(int u,int now) {
    loc[u]=++all; num[all]=u; dep[all]=now;
    for (int i = head[u]; ~i; i = edge[i].nxt)
    {
        int v = edge[i].to;
        if (loc[v]) continue;
        dfs(v,now+1);
        num[++all]=u;
        dep[all]=now;
    }
}
void initRMQ() {
  LOG[0] = -1;
  for(int i = 1;i <= all; i++) {
      dp[0][i] = dep[i];
      point[0][i] = num[i];
      LOG[i] = ((i&(i-1)) == 0) ? LOG[i-1]+1 : LOG[i-1];
  }
  for (int i = 1; (1<<i) <= all; ++i) {
    for (int j = 1; j+(1<<i)-1 <= all; ++j) {
      if (dp[i-1][j] < dp[i-1][j+(1<<(i-1))]) {
        dp[i][j] = dp[i-1][j];
        point[i][j] = point[i-1][j];
      } else {
        dp[i][j] = dp[i-1][j+(1<<(i-1))];
        point[i][j] = point[i-1][j+(1<<(i-1))];
      }
    }
  }
}
int queryRMQ(int l, int r) {
  l = loc[l]; r = loc[r];
  if (l > r) swap(l, r);
  int k = LOG[r-l+1];
  /*
  貌似下面這種寫法更快
  記得把上面預處理的LOG刪了
   P 3379

  int k=0;
  while((1<<k)<=r-l+1) k++;
  k--;
  */
  if(dp[k][l] < dp[k][r-(1<<k)+1]) return point[k][l];
  else return point[k][r-(1<<k)+1];
}
void preWork(int u, int fa, int now) {
    val[u] = now;
    par[u] = fa;
    for (int i = head[u]; ~i; i = edge[i].nxt) {
        int to = edge[i].to;
        if (to == fa) continue;
        preWork(to, u, now+1);
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.precision(10);
    cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("input.txt", "r", stdin);
#endif

    ms(head, -1);
    ms(loc, 0);
    ms(par, -1);
    cin >> n >> m;
    forn(i, n-1) {
        int u, v;
        cin >> u >> v;
        addEdge(u, v);
        addEdge(v, u);
    }
    dfs(1, 1);
    initRMQ();
    preWork(1, -1, 1);
    forn(i, m) {
        vector< pair<int, int> > res;
        int k, x;
        cin >> k;
        while (k--) {
            cin >> x;
            if (par[x] != -1) x = par[x];
            res.eb(mp(val[x], x));
        }
        sort(all(res));
        int len = SZ(res);
        bool ok = true;
        for (int i = 0; i < len-1; ++i) {
            int temp = queryRMQ(res[i].se, res[len-1].se);
            if (temp != res[i].se) {
                ok = false;
                break;
            }
        }
        cout << (ok ? "YES" : "NO") << '\n';
    }

#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}

F
題意:
給你n個數,現在給你兩個操作:
1.把這n個數裏最大的那個數-1
2.把這n個數裏最小的那個數+1
現在問你最少要多少次操作才能得到至少k個相同的數。

思路:
看了這位巨巨的博客,才懂得,假設結果k個相同的數是兩個數之間的某個數,付出的代價肯定比取兩個數其中的一個數來的大,所以枚舉每一個數作爲最後的答案,要獲得這個數要麼全都是左邊(先變成a[i]-1)來的,要麼全都是右邊來(先變成a[i]+1)的,要麼兩邊都有,維護一下答案就完事了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章