void dfs(int u,int fa)
{
d[u]=d[fa]+1;
sz[u]=1;
int ma=-1;
for(int v:g[u])
{
if(v==fa)continue;
dfs(v,u);
sz[u]+=sz[v];
if(sz[v]>ma)
{
ma=sz[v];
son[u]=v;
}
}
}
给定一个以1为根的n个节点的树,每个点上有一个字母(a-z),
每个点的深度定义为该节点到1号节点路径上的点数.
每次询问 a,b.查询以a为根的子树内深度为b的节点上的字母重新排列之后是否能构成回文串.
void cal(int u,int fa,int f)
{
cnt[d[u]][col[u]]+=f;
for(int v:g[u])
{
if(v==fa|v==now)continue;
cal(v,u,f);
}
}
void dfs(int u,int fa,int f)
{
for(int v:g[u])
{
if(v==fa||v==son[u])continue;
dfs(v,u,0);
}
if(son[u])dfs(son[u],u,1)now=son[u];
cal(u,fa,1);
for(int i=0;i<q[u].size();i++)
{
int d=q[u][i].y;
int id=q[u][i].x;
int num=0;
for(int i=1;i<=26;i++)
{
if(cnt[d][i]&1)num++;
}
ans[id]=num>1?0:-1;
}
now=0;
if(!f)cal(u,fa,-1);
}
给你一片森林,每次询问一个点与多少个点拥有共同的K级祖先
问题转化为 他的k级祖先上有多少个深度相同的儿子
我们先离线询问
void dfs(int u,int fa)
{
d[u]=d[fa]+1;
f[u][0]=fa;
for(int i=1;i<=20;i++)
{
fa[u][i]=fa[fa[u][i-1]][i-1];
}
for(int v:g[u])
{
if(v==fa)continue;
dfs(v,u);
}
}
int cal(int u,int fa,int f)
{
cnt[d[u]]+=1;
for(int v:g[u])
{
if(v==fa||v==now)continue;
cal(v,u,f);
}
}
void dfs(int u,int fa,int f)
{
for(int v:g[u])
{
if(v==fa||v==son[u])continue;
dfs(v,u,0);
}
if(son[u]){
dfs(son[u],u,1);
now=son[u];
}
cal(u,fa,1);
for(int i=0;i<q[u].size();i++)
{
int id=q[u][i].x;
int d=q[u][i].y;
ans[id]=cnt[d]-1;
}
now=0;
if(!f)cal(u,fa,-1);
}
for(int j=20;j>=0;j--)
{
if(p&(1<<j))
u=fa[u][j];
}
q[u].pb({i,d});
给定一片森林,每次询问一个节点的K-Son共有个多少不同的名字。一个节点的K-Son即为深度是该节点深度加K的节点。
map维护
map<string,int>a[N];
void cal(int u,int fa,int f)
{
if(!a[d[u]][s[u]]) cnt[d[u]]+=f;
a[d[u]][s[u]]+=f;
if(!a[d[u]][s[u]]) cnt[d[u]]-=f;
for(int v:g[u])
{
if(v==fa||v==now)continue;
cal(v,u,f);
}
}
for(int i=0;i<q[u].size();i++)
{
int id=q[u][i].x;
int d=q[u][i].y;
ans[id]=cnt[d];
}
for(int i=1;i<=m;i++)
{
int x,y;
q[x].pb({i,d[x]+y});
}
给定一棵以 1 为根,n 个节点的树。设 d(u,x)为 u 子树中到 u 距离为 x 的节>点数。
对于每个点,求一个最小的 k,使得 d(u,k) 最大。
void cal(int u,int fa,int f)
{
cnt[d[u]]+=f;
if(f>0&&cntd[d[u]]>=mac)
{
if(cnt[d[u]]>mac){
mac=cnt[d[u]];
mi=d[u];
}
else if(cnt[d[u]]==mac&&d[u]<mi){
mi=d[u];
}
}
for(int v:g[u])
{
if(v==fa||v==now)continue;
cal(v,u,f);
}
}
void dfs(int u,int fa,int f)
{
for(int v:g[u])
{
if(v==fa||v==son[u])continue;
dfs(v,u,0);
}
if(son[u]){
dfs(son[u],u,1);
now=son[u];
}
cal(u,fa,1);
ans[u]=mi-d[u];
now=0;
if(!f)cal(u,f,-1),mi=inf,mxc=0;
}
给出一棵 n 个结点的树,每个结点有一个颜色 c i 。
询问 q 次,每次询问以 v 结点为根的子树中,出现次数 ≥k 的颜色有多少种。树的根节点是1。
cnt[N] 表示出现次数大于等于k的种类数
void cal(int u,int fa,int f)
{
if(f=-1)num[cnt[col[u]]]+=f;
cnt[col[u]]+=f;
if(f==1)num[cnt[col[u]]]+=f;
for(int v:g[u])
{
if(v==fa||v==now)continue;
dfs(v,u,f);
}
}
for(int i=0;i<q[u].size();i++)
{
int id=q[u][i].x;
int k=q[u][i].y;
ans[id]=num[k];
}
给你一个n个节点的树,求每个节点的"结实程度"
一个节点的结实程度定义为以该节点为根的子树里所有节点的编号从小到大>排列后,相邻编号的平方和。
void calc(int u, int f, int k)
{
if (k == 1)
{
if (s.empty())
s.insert(u);
else
{
if (s.lower_bound(u) == s.end())
{
set<int>::iterator it = s.end();
it--;
sum += 1ll*(u - *it) * (u - *it);
}
else if (s.lower_bound(u) == s.begin())
{
set<int>::iterator it = s.begin();
sum += 1ll*(*it - u) * (*it - u);
}
else
{
set<int>::iterator it = s.lower_bound(u);
set<int>::iterator it1 = it;
it1--;
sum -= 1ll*(*it - *it1) * (*it - *it1);
sum += 1ll*(u - *it1) * (u - *it1);
sum += 1ll*(*it - u) * (*it - u);
}
s.insert(u);
}
}
else
s.erase(u);
for (auto v : G[u])
if (v!=now && v != f)
calc(v, u, k);
}