「CF741D」Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths

传送门
Luogu

解题思路

考虑把22个字符状压下来,易知合法情况就是状态中之多有一个1,这个可以暴力一点判断23次。
然后后就是 dsu on the tree 了。

细节注意事项

  • 咕咕咕

参考代码

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cctype>
#include <cmath>
#include <ctime>
#define rg register
using namespace std;
template < typename T > inline void read(T& s) {
    s = 0; int f = 0; char c = getchar();
    while (!isdigit(c)) f |= (c == '-'), c = getchar();
    while (isdigit(c)) s = s * 10 + (c ^ 48), c = getchar();
    s = f ? -s : s;
}

const int _ = 500010;

int tot, head[_], nxt[_ << 1], ver[_ << 1], w[_ << 1];
inline void Add_edge(int u, int v, int d)
{ nxt[++tot] = head[u], head[u] = tot, ver[tot] = v, w[tot] = d; }

int n, dis[_], tg[1 << 22 | 2];
int dep[_], siz[_], son[_], ans[_];
int num, L[_], R[_], id[_];

inline void dfs(int u, int f) {
    siz[u] = 1, dep[u] = dep[f] + 1;
    L[u] = ++num, id[num] = u;
    for (rg int i = head[u]; i; i = nxt[i]) {
        int v = ver[i]; if (v == f) continue;
        dis[v] = dis[u] ^ w[i];
        dfs(v, u), siz[u] += siz[v];
        if (siz[v] > siz[son[u]]) son[u] = v;
    }
    R[u] = num;
}

inline void dfss(int u, int f, int keep) {
    for (rg int i = head[u]; i; i = nxt[i]) {
        int v = ver[i]; if (v == f || v == son[u]) continue;
        dfss(v, u, 0), ans[u] = max(ans[u], ans[v]);
    }
    if (son[u]) dfss(son[u], u, 1), ans[u] = max(ans[u], ans[son[u]]);
    if (tg[dis[u]]) ans[u] = max(ans[u], tg[dis[u]] - dep[u]);
    for (rg int k = 0; k < 22; ++k)
        if (tg[dis[u] ^ (1 << k)])
            ans[u] = max(ans[u], tg[dis[u] ^ (1 << k)] - dep[u]);
    tg[dis[u]] = max(tg[dis[u]], dep[u]);
    for (rg int i = head[u]; i; i = nxt[i]) {
        int v = ver[i]; if (v == son[u] || v == f) continue;
        for (rg int x = L[v]; x <= R[v]; ++x) {
            int p = id[x];
            if (tg[dis[p]]) ans[u] = max(ans[u], tg[dis[p]] + dep[p] - 2 * dep[u]);
            for (rg int k = 0; k < 22; ++k)
                if (tg[dis[p] ^ (1 << k)]) ans[u] = max(ans[u], tg[dis[p] ^ (1 << k)] + dep[p] - 2 * dep[u]);
        }
        for (rg int x = L[v]; x <= R[v]; ++x)
            tg[dis[id[x]]] = max(tg[dis[id[x]]], dep[id[x]]);
    }
    if (!keep) for (rg int x = L[u]; x <= R[u]; ++x) tg[dis[id[x]]] = 0;
}

int main() {
#ifndef ONLINE_JUDGE
    freopen("in.in", "r", stdin);
#endif
    read(n);
    for (rg int p, i = 2; i <= n; ++i) {
        read(p); char c = getchar();
        while (!isalpha(c)) c = getchar();
        Add_edge(p, i, 1 << (c - 'a'));
        Add_edge(i, p, 1 << (c - 'a'));
    }
    dfs(1, 0), dfss(1, 0, 1);
    for (rg int i = 1; i <= n; ++i)
        printf("%d%c", ans[i], " \n"[i == n]);
    return 0;
}

完结撒花 \(qwq\)

原文地址:https://www.cnblogs.com/zsbzsb/p/11746532.html

时间: 2024-10-06 19:25:46

「CF741D」Arpa’s letter-marked tree and Mehrdad’s Dokhtar-kosh paths的相关文章

「CF1039D」You Are Given a Tree

传送门 Luogu 解题思路 整体二分. 的确是很难看出来,但是你可以发现输出的答案都是一些可以被看作是关键字处于 \([1, n]\) 的询问,而答案的范围又很显然是 \([0, n]\),这不就刚好满足了整体二分的几个组成部分了吗. 那么我们要如何求出 \(mid\) 位置的解呢? 考虑 \(\text{DP}\) 我们很显然可以将子树中的点尽可能合并后再向父亲传递,所以我们对每一次DP的根节点分别记一个子树中的最大值,和一个非严格次大值,然后我们尝试合并这两个值,要是合并不了,就给答案加一

「SPOJ1487」Query on a tree III

「SPOJ1487」Query on a tree III 传送门 把树的 \(\text{dfs}\) 序抠出来,子树的节点的编号位于一段连续区间,然后直接上建主席树区间第 \(k\) 大即可. 参考代码: #include <algorithm> #include <cstdio> #define rg register #define file(x) freopen(x".in", "r", stdin), freopen(x"

「SPOJ10707」Count on a tree II

「SPOJ10707」Count on a tree II 传送门 树上莫队板子题. 锻炼基础,没什么好说的. 参考代码: #include <algorithm> #include <cstdio> #include <cmath> #define rg register #define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w

「luogu2633」Count on a tree

「luogu2633」Count on a tree 传送门 树上主席树板子. 每个节点的根从其父节点更新得到,查询的时候差分一下就好了. 参考代码: #include <algorithm> #include <cstdio> #define rg register #define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", s

LibreOJ #2016. 「SCOI2016」美味

二次联通门 : LibreOJ #2016. 「SCOI2016」美味 /* LibreOJ #2016. 「SCOI2016」美味 dalao们都在说这题如果没有加法balabala就可以用可持久化trie解决了 然而我连那个也不会啊QAQ 此题用主席树 从高位到低位贪心 能填1就填1,也就是查询一段区间有没有某个范围的数 (然而由乃dalao说可持久化线段树和可持久化trie是一个东西) */ #include <cstdio> #include <iostream> #inc

「一」创建一个带 ssh 服务的基础镜像(修订版)--使用「docker commit」创建

在介绍如何创建带 ssh 服务的基础镜像之前,我们想回顾一下之前介绍过的内容,其中提到有三种创建镜像的常用办法: 从文件系统导入 从现有容器使用「docker commit」提交 使用 dockerfile 文件 build 本章将主要介绍后面 2 种方法. 步骤如下: $ sudo docker run -ti ubuntu:14.04 /bin/bash #首先,使用我们最熟悉的 「-ti」参数来创建一个容器. [email protected]:/# sshd bash: sshd: co

Loj #3111. 「SDOI2019」染色

Loj #3111. 「SDOI2019」染色 题目描述 给定 \(2 \times n\) 的格点图.其中一些结点有着已知的颜色,其余的结点还没有被染色.一个合法的染色方案不允许相邻结点有相同的染色. 现在一共有 \(c\) 种不同的颜色,依次记为 \(1\) 到 \(c\).请问有多少对未染色结点的合法染色方案? 输入格式 第一行有两个整数 \(n\) 和 \(c\),分别描述了格点图的大小和总的颜色个数. 之后两行,每行有 \(n\) 个整数:如果是 \(0\) 则表示对应结点未被染色,否

「SCOI2012」喵星球上的点名

「SCOI2012」喵星球上的点名 填一个很久以前用 \(\texttt{AC}\) 自动机没填上的坑. 关于本题,能够通过本题的算法很多,这里作者采用的是后缀数组+树状数组的做法. 首先有一个显然的结论:若 \(s_2\) 是 \(s_1\) 的子串,则 \(s_1\) 一定存在一个后缀与 \(s_2\) 的最长公共前缀为 \(|s_2|\). 我们将读入的姓.名.询问串连成一个整体,形成一个字符串 \(s\),且在每一个姓.名.询问串中插入一个不存在文本中的字符,且保证询问串后插入的比姓名串

AC日记——「HNOI2017」单旋 LiBreOJ 2018

#2018. 「HNOI2017」单旋 思路: set+线段树: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 100005 #define maxtree maxn<<2 int val[maxtree],tag[maxtree],L[maxtree],R[maxtree],mid[maxtree]; int op[maxn],ki[maxn],bi[maxn],cnt,size,n,ch[maxn]