对于树上的一个节点 u u u,按照以下步骤执行:
一般来说,没有修改、只对子树进行询问(或者转化成子树的答案) 就可以用 dsu on tree。
根节点到任意节点的轻边数不超过 l o g n logn logn 条。设根节点 r o o t root root 到节点 u u u 的路径中有 x x x 条轻边,以 u u u 为根的子树大小为 y y y ,则 1 ≤ y < n / 2 x 1 \le y < n/2^x 1≤y<n/2x ,所以 x < l o g x x < logx x<logx 。重边不会被额外遍历。所以每个节点被遍历到的次数为 l o g n + 1 logn + 1 logn+1
时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)
询问子树内出现次数最多的颜色的编号和
#include
#include
#include
#include
using namespace std;
typedef long long ll;
#define int ll
const int N = 1e5+10;
int head[N], tot;
int son[N], size[N], pa[N];
int ans[N], cnt[N], col[N], sum, Max, Son;
int n;
struct edge{
int to, nxt;
}e[N<<1];
void addedge(int a, int b){
e[++tot].nxt = head[a];
e[tot].to = b;
head[a] = tot;
}
inline int read(){//读入优化
char ch;
while((ch=getchar())<'0'||ch>'9');
int res = ch-48;
while((ch=getchar())>='0'&&ch<='9')
res = res*10+ch-48;
return res;
}
void update(int x, int val){
cnt[col[x]] += val;
if(cnt[col[x]] > Max){
Max = cnt[col[x]];
sum = col[x];
}
else if(cnt[col[x]] == Max)
sum += col[x];
for(int i = head[x]; i; i = e[i].nxt){
int v = e[i].to;
if(v == pa[x] || v == Son)
continue;
update(v, val);
}
}
void dfs1(int u, int fa){
size[u] = 1;
pa[u] = fa;
for(int i = head[u]; i; i = e[i].nxt){
int v = e[i].to;
if(v == fa)
continue;
dfs1(v, u);
size[u] += size[v];
if(size[v] > size[son[u]])
son[u] = v;
}
}
void dfs2(int u, int flag){
for(int i = head[u]; i; i = e[i].nxt){
int v = e[i].to;
if(v == pa[u] || v == son[u])
continue;
dfs2(v, 0);
}
if(son[u])
dfs2(son[u], 1), Son = son[u];
update(u, 1);
ans[u] = sum; Son = 0;
if(flag == 0)
update(u, -1), sum = Max = 0;
}
signed main(){
n = read();
for(int i = 1; i <= n; i++)
col[i] = read();
for(int i = 1; i <= n-1; i++){
int u, v;
u = read(), v = read();
addedge(u, v);
addedge(v, u);
}
dfs1(1, 0);
dfs2(1, 0);
for(int i = 1; i <= n; i++)
printf("%lld ", ans[i]);
return 0;
}
n n n 个节点的树,每个点上都有一个小写字母。m次询问,每次询问以 a a a 为根的子树内深度为 b b b 的节点重新排列后能否构成回文串(深度是在整棵树中的深度)
一个回文串中,只有一个字符能够出现奇数次。
对于以 u u u 为根的子树,处理所有的字符,记录每个深度下字符的数量。处理完之后解决在 u u u 子树中的询问
#include
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
const int N = 5E5+10;
int size[N], dep[N], son[N], pa[N], dfn[N], seg[N];
int s[N], cnt[N][30], ans[N];
int n, m, dfntot, tot, head[N];
inline int read(){//读入优化
char ch;
while((ch=getchar())<'0'||ch>'9');
int res = ch-48;
while((ch=getchar())>='0'&&ch<='9')
res = res*10+ch-48;
return res;
}
struct node{
int x, y;
};
vector<node> q[N];
struct edge{
int to, nxt;
}e[N<<1];
inline void addedge(int a, int b){
e[++tot].nxt = head[a];
e[tot].to = b;
head[a] = tot;
}
inline void add(int x){
cnt[dep[x]][s[x]]++;
}
inline void update(int x){
for(int i = seg[x]; i <= seg[x]+size[x]-1; i++)
add(dfn[i]);
}
inline void del(int x){
cnt[dep[x]][s[x]] = 0;
}
void clear(int x){
for(int i = seg[x]; i <= seg[x]+size[x]-1; i++)
del(dfn[i]);
}
inline int check(int x){
int res = 0;
for(int i = 1; i <= 26; i++)
if(cnt[x][i]&1)
res++;
return res <= 1;
}
void dfs1(int u, int fa){
dep[u] = dep[fa]+1;
size[u] = 1;
seg[u] = ++dfntot;
dfn[dfntot] = u;
for(int i = head[u]; i; i = e[i].nxt){
int v = e[i].to;
if(v == fa)
continue;
dfs1(v, u);
size[u] += size[v];
if(size[v] > size[son[u]])
son[u] = v;
}
}
void dfs2(int u, int flag){
for(int i = head[u]; i; i = e[i].nxt){
int v = e[i].to;
if(v==son[u]||v==pa[u])
continue;
dfs2(v, 0);
}
if(son[u])
dfs2(son[u], 1);
for(int i = head[u]; i; i = e[i].nxt){
int v = e[i].to;
if(v == son[u]||v == pa[u])
continue;
update(v);
}
add(u);
for(int i = 0; i < q[u].size(); i++)
ans[q[u][i].y] = check(q[u][i].x);
if(flag == 0)
clear(u);
}
int main(){
n = read(); m = read();
for(int i = 2, x; i <= n; i++){
x = read();
pa[i] = x;
addedge(x, i);
}
string ss; cin >> ss;
for(int i = 1; i <= n; i++)
s[i] = ss[i-1]-'a'+1;
for(int i = 1, x, y; i <= m; i++){
x = read(); y = read();
q[x].push_back((node){y, i});
}
dfs1(1, 0);
dfs2(1, 0);
for(int i = 1; i <= m; i++){
ans[i] ? puts("Yes") : puts("No");
}
return 0;
}
给定一个森林,每次询问 ( v , p ) (v,p) (v,p),节点 v v v 的 p-cousin 的个数。若 u u u 与 v v v 深度相同且 u u u 到 l c a ( u , v ) lca(u,v) lca(u,v) 的距离小于 p p p ,则 u u u 是 v v v 的 p-cousin
对于询问 ( v , p ) (v,p) (v,p),找到到 v v v 的距离为 p p p 的祖先节点 f a fa fa ,在以 f a fa fa 为根的子树内,计算到 f a fa fa 距离为 p p p 节点的数量,然后减 1 1 1。
#include
#include
#include
using namespace std;
const int N = 1E5+10;
const int M = 1e5+10;
const int INF = 0x3f3f3f3f;
inline int read(){//读入优化
char ch;
while((ch=getchar())<'0'||ch>'9');
int res = ch-48;
while((ch=getchar())>='0'&&ch<='9')
res = res*10+ch-48;
return res;
}
int head[N], dep[N], ans[N], dfn[N], rev[N];
int p[N][20], cnt[N];
int size[N], son[N];
int n, tot, dfntot, m;
struct edge{
int to, nxt;
}e[N<<1];
void addedge(int a, int b){
e[++tot].nxt = head[a];
e[tot].to = b;
head[a] = tot;
}
struct node{
int k, id;
};
vector<node> q[N];
void add(int x){
cnt[dep[x]]++;
}
void update(int x){
for(int i = dfn[x]; i <= dfn[x]+size[x]-1; i++)
add(rev[i]);
}
void del(int x){
cnt[dep[x]] --;
}
void clear(int x){
for(int i = dfn[x]; i <= dfn[x]+size[x]-1; i++)
del(rev[i]);
}
int find_fa(int x, int y){
for(int i = 18; i >= 0; i--){
if(y >= (1<<i)){
y -= (1<<i);
x = p[x][i];
}
}
return x;
}
void dfs1(int x, int fa){
dep[x] = dep[fa]+1;
size[x] = 1;
dfn[x] = ++dfntot;
rev[dfntot] = x;
for(int i = 1; i <= 18; i++)
p[x][i] = p[p[x][i-1]][i-1];
for(int i = head[x]; i; i = e[i].nxt){
int v = e[i].to;
dfs1(v, x);
size[x] += size[v];
if(size[v] > size[son[x]])
son[x] = v;
}
}
void dfs2(int x, int flag){
for(int i = head[x]; i; i = e[i].nxt){
int v = e[i].to;
if(v == son[x])
continue;
dfs2(v, 0);
}
if(son[x])
dfs2(son[x], 1);
for(int i = head[x]; i; i = e[i].nxt){
int v = e[i].to;
if(v == son[x])
continue;
update(v);
}
add(x);
for(int i = 0; i < q[x].size(); i++)
ans[q[x][i].id] = cnt[dep[x]+q[x][i].k];
if(!flag)
clear(x);
}
int main(){
n = read();
for(int i = 1, x; i <= n; i++){
x = read();
p[i][0] = x;
addedge(x, i);
}
for(int i = 1; i <= n; i++)
if(p[i][0] == 0)
dfs1(i, 0);
m = read();
for(int i = 1; i <= m; i++){
int x, y, z;
x = read(), y = read();
z = find_fa(x, y);
if(z)
q[z].push_back((node){y, i});
}
for(int i = 1; i <= n; i++){
if(p[i][0] == 0)
dfs2(i, 0);
}
for(int i = 1; i <= m; i++)
printf("%d ", max(ans[i]-1, 0));
return 0;
}
https://blog.csdn.net/qq_35975367/article/details/119134160
https://oi-wiki.org/graph/dsu-on-tree/