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)的,要么两边都有,维护一下答案就完事了。