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)的,要麼兩邊都有,維護一下答案就完事了。