CF1916E Happy Life in University
TernaryTree · · 题解
想题五分钟,卡常五小时/fn/fn/fn/oh/oh/oh 诋毁出题人!!
upd 2024.1.10:我错了对不起出题人,我深深忏悔,原因是我下面第一份写的看似正确的代码实际上复杂度假了。
个人觉得比 D 简单几十倍啊,D 可以定性为:天赋哥题。相比之下这个题就比较不需要脑子。
我们考虑怎么去数一条自上而下的链上的不同权值数量,这个是非常非常经典的 trick 啊:记录
void dfs1(int u) {
int l = bk[a[u]];
lst[u] = l;
bk[a[u]] = u;
for (int v : g[u]) dfs1(v);
bk[a[u]] = l;
}
考虑去枚举这个
void dfs1(int u) {
dfn[u] = ++idx, siz[u] = 1;
p[lst[u] = bk[a[u]]].push_back(u);
int l = bk[a[u]];
bk[a[u]] = u;
for (int v : g[u]) dfs1(v), siz[u] += siz[v];
bk[a[u]] = l;
}
void dfs2(int u, int fa) {
for (int y : p[fa]) add(rt, dfn[y], dfn[y] + siz[y] - 1, 1);
int mx = 1, sc = 1;
int q = fa ? query(rt, dfn[fa], dfn[fa]) : 0;
for (int v : g[u]) {
int y = query(rt, dfn[v], dfn[v] + siz[v] - 1) - q;
if (y > mx) sc = mx, mx = y;
else if (y > sc) sc = y;
}
for (int v : g[u]) dfs2(v, u);
if ((ll) mx * sc > ans) ans = (ll) mx * sc;
for (int y : p[fa]) add(rt, dfn[y], dfn[y] + siz[y] - 1, -1);
}
然而善良美好的出题人并不愿意让我们这样轻而易举地通过这道题,所以在这样一个线段树跑
upd:上面那份代码复杂度假了。可以不用看了。
卡常!经过我真挚诚恳的求问,最终得到了
具体地:
void dfs1(int u) {
dfn[u] = ++idx, siz[u] = 1;
int l = bk[a[u]];
lst[u] = l;
bk[a[u]] = u;
for (int v : g[u]) dfs1(v), siz[u] += siz[v];
bk[a[u]] = l;
}
void dfs2(int u, int fa) {
for (int v : g[u]) dfs2(v, u);
add(rt, dfn[u], dfn[u] + siz[u] - 1, 1);
for (int y : p[u]) add(rt, dfn[y], dfn[y] + siz[y] - 1, -1);
int mx = 1, sc = 1;
int q = fa ? query(rt, dfn[fa], dfn[fa]) : 0;
for (int v : g[u]) {
int y = query(rt, dfn[v], dfn[v] + siz[v] - 1) - q;
if (y > mx) sc = mx, mx = y;
else if (y > sc) sc = y;
}
if ((ll) mx * sc > ans) ans = (ll) mx * sc;
p[lst[u]].push_back(u);
}
首先把儿子优先扔下去 dfs,然后把
老话说得好:细节决定成败。常数这种东西看似细枝末节,而许许多多的人都在编写代码的过程中忽略了自己的常数,而这样的小细节才是出题人要求选手达到的境界。这也侧面反映出作为一名 OI 选手,我的 OI 造诣和自我修养不足,理解不了这种内在的阳春白雪的高雅艺术,只能看到外表的辞藻堆砌,参不透其中深奥的精神内核,我整个人的层次就卡在这里了,只能度过一个相对失败的人生。希望大家引以为戒。在此,我深深忏悔,并收回文章开头对出题人的诋毁,非常好题目,为出题人点赞。
2024.1.10 反转了,复杂度假了。老话说得好,复杂度决定成败,后面忘了,希望大家能自行补全。