给定有根树,定义d[x,i]表示以x为根的树中,与x的距离为i的节点个数,对于每棵子树,求出使得d[x,i]最大的i,存在多个输出最小的。
其实是一道dsu on tree的模板题了…
正解:cnt[i]
表示当前子树深度为i的节点个数,每次更新都是用的当前子树的节点进行更新,所以可以直接用全局变量维护最大值,然后更新就行。
但是这题卡常,刚开始add函数是用递归写的,就t了,改成dfs序很快就跑完了。
递归:
dfs序:
#include<bits/stdc++.h>
using namespace std;
//#pragma GCC optimize(2)
#define ull unsigned long long
#define ll long long
#define pii pair<int, int>
#define lc rt<<1
#define rc rt<<1|1
const int maxn = 1e6 + 10;
const ll mod = 1e9+7;
const ll inf = (ll)4e17;
const double pi = acos(-1.0);
ll inv(ll b){
if(b==1)return 1;return(mod-mod/b)*inv(mod%b)%mod;}
//给定有根树 定义d(x,i)为x的后代中 深度比x多i的节点个数 对于每个x 求d数组的最大值下标
//用全局变量维护d数组的最大值
int n,m;
vector<int> g[maxn];
int dep[maxn],son[maxn],size[maxn],in[maxn],clk,pos[maxn];
int ans[maxn];
int idx=maxn,mmax=-1;
int d[maxn];//深度为i 个数
void dfs(int rt,int fa)
{
dep[rt]=dep[fa]+1;
in[rt]=++clk;
pos[clk]=rt;
size[rt]=1;
for(int i:g[rt])
{
if(i==fa) continue;
dfs(i,rt);
size[rt]+=size[i];
if(size[i] > size[son[rt]]) son[rt]=i;
}
}
int SON;
void add(int rt,int v)
{
for(int i=in[rt];i<in[rt]+size[rt];i++)
{
//pos[i] 就是节点
int u=pos[i];
if(u==SON)
{
i=i+size[SON]-1;//跳过SON的整棵子树
continue;
}
d[dep[u]]+=v;
if(d[dep[u]]>mmax || (d[dep[u]]==mmax && dep[u]<idx))
{
mmax=d[dep[u]];
idx=dep[u];
}
}
}
void dfs2(int rt,int fa,bool ok)
{
for(int i:g[rt])
{
if(i==fa || i==son[rt]) continue;
dfs2(i,rt,0);
}
if(son[rt]) dfs2(son[rt],rt,1),SON=son[rt];
add(rt,1),SON=0;
ans[rt]=idx-dep[rt];
if(!ok) add(rt,-1),mmax=-1,idx=maxn;//删除后 全局维护的变量也要记得清空
}
int main()
{
scanf("%d",&n);
for(int i=1,u,v;i<n;i++)
{
scanf("%d %d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
dfs(1,0);
dfs2(1,0,0);
for(int i=1;i<=n;i++)
{
printf("%d\n",ans[i]);
}
return 0;
}
题外话:
or这题的第一反应想复杂了,觉得对于子树rt是在cnt数组[dep[rt],n]
中取最大值,想到用线段树维护,单点修改区间查询。O(nlognlogn)
不过用线段树写完居然可以过…(当然add函数还是用的dfs序,用递归也t了)
加上线段树的版本:
#include<bits/stdc++.h>
using namespace std;
//#pragma GCC optimize(2)
#define ull unsigned long long
#define ll long long
#define pii pair<int, int>
#define lc rt<<1
#define rc rt<<1|1
const int maxn = 1e6 + 10;
const ll mod = 1e9+7;
const ll inf = (ll)4e17;
const double pi = acos(-1.0);
ll inv(ll b){
if(b==1)return 1;return(mod-mod/b)*inv(mod%b)%mod;}
//给定有根树 定义d(x,i)为x的后代中 深度比x多i的节点个数 对于每个x 求d数组的最大值下标
//dsu on tree 线段树维护d[] 深度为i的点的个数 每次查询[dep[rt],n]最大值
//nlognlogn
pii tree[maxn<<2];//fi 个数 se 深度
inline void pushup(int rt)
{
if(tree[lc].first != tree[rc].first)
tree[rt]=max(tree[lc],tree[rc]);
else
{
if(tree[lc].second < tree[rc].second) tree[rt]=tree[lc];
else tree[rt]=tree[rc];
}
}
inline void build(int rt,int l,int r)
{
if(l==r)
{
tree[rt].first=0;
tree[rt].second=l;
return ;
}
int mid=l+r>>1;
build(lc,l,mid);build(rc,mid+1,r);
pushup(rt);
}
inline void upd(int rt,int l,int r,int pos,int v)
{
if(l==r)
{
tree[rt].first+=v;
return ;
}
int mid=l+r>>1;
if(pos<=mid) upd(lc,l,mid,pos,v);
else upd(rc,mid+1,r,pos,v);
pushup(rt);
}
inline pii qry(int rt,int l,int r,int vl,int vr)
{
if(vl<=l && r<=vr) return tree[rt];
int mid=l+r>>1;
if(vr<=mid) return qry(lc,l,mid,vl,vr);
else if(vl>mid) return qry(rc,mid+1,r,vl,vr);
pii t1=qry(lc,l,mid,vl,vr),t2=qry(rc,mid+1,r,vl,vr);
if(t1.first != t2.first) return max(t1,t2);
else
{
if(t1.second < t2.second) return t1;
else return t2;
}
}
int n,m;
vector<int> g[maxn];
int dep[maxn],son[maxn],size[maxn],in[maxn],clk,pos[maxn];
int ans[maxn];
void dfs(int rt,int fa)
{
dep[rt]=dep[fa]+1;
in[rt]=++clk;
pos[clk]=rt;
size[rt]=1;
for(int i:g[rt])
{
if(i==fa) continue;
dfs(i,rt);
size[rt]+=size[i];
if(size[i] > size[son[rt]]) son[rt]=i;
}
}
int SON;
void add(int rt,int v)
{
for(int i=in[rt];i<in[rt]+size[rt];i++)
{
int u=pos[i];
if(u==SON)
{
i=i+size[SON]-1;
continue;
}
upd(1,1,n,dep[u],v);
}
/* upd(1,1,n,dep[rt],v);
for(int i:g[rt])
{
if(i==fa || i==SON) continue;
add(i,rt,v);
}
*/
}
void dfs2(int rt,int fa,bool ok)
{
for(int i:g[rt])
{
if(i==fa || i==son[rt]) continue;
dfs2(i,rt,0);
}
if(son[rt]) dfs2(son[rt],rt,1),SON=son[rt];
add(rt,1),SON=0;
ans[rt]=qry(1,1,n,dep[rt],n).second-dep[rt];
if(!ok) add(rt,-1);
}
int main()
{
scanf("%d",&n);
for(int i=1,u,v;i<n;i++)
{
scanf("%d %d",&u,&v);
g[u].push_back(v);
g[v].push_back(u);
}
build(1,1,n);
dfs(1,0);
dfs2(1,0,0);
for(int i=1;i<=n;i++)
printf("%d\n",ans[i]);
return 0;
}