这题我想到了dfs序+线段树的解法,感觉挺好的,就是思路出的有点慢了,听说正解是一个简单dfs(),不过那个思路我没怎么想,我想过拟spfa()的写法,好像有点麻烦,之后想到
dfs序+线段树
,然后尝试四发A了
题解:
我们取出每个节点的dfs序,把每个节点赋予它的
深度-1
的权值,然后我们只需要求出我们查询的节点u,以其为根节点,连带的子树的权值和,然后用和减去这个子树的节点数量*
u节点的权值,就是答案,权值和用线段树取维护即可
AC代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=1e5+5;
ll deep[maxn],dfn[maxn],head[maxn],sizx[maxn];
ll a[maxn];
struct node
{
ll to,nex;
} edge[maxn<<1];
ll cnt,cnx;
void add(ll u,ll v)
{
edge[cnt].to=v;
edge[cnt].nex=head[u];
head[u]=cnt++;
}
void dfs(ll u,ll fa)
{
deep[u]=deep[fa]+1;
sizx[u]=1;
dfn[u]=++cnx;
a[cnx]=deep[u]-1;
for(ll i=head[u]; ~i; i=edge[i].nex)
{
ll v=edge[i].to;
if(v!=fa)
{
dfs(v,u);
sizx[u]+=sizx[v];
}
}
}
struct vain
{
ll l,r,sum;
} tr[maxn<<2];
void pushup(ll k)
{
tr[k].sum=tr[k<<1].sum+tr[k<<1|1].sum;
}
void build(ll k,ll l,ll r)
{
tr[k].l=l,tr[k].r=r;
if(l==r)
{
tr[k].sum=(a[l]);
//cout<<tr[k].sum<<endl;
return ;
}
ll mid=l+r>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
pushup(k);
}
ll ask(ll k,ll l,ll r)
{
if(tr[k].l>=l&&tr[k].r<=r)
{
return tr[k].sum;
}
ll mid=tr[k].l+tr[k].r>>1;
if(mid>=r)
{
return ask(k<<1,l,r);
}
else if(mid<l)
{
return ask(k<<1|1,l,r);
}
else
{
return ask(k<<1,l,mid)+ask(k<<1|1,mid+1,r);
}
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cnx=0;
cnt=0;
memset(head,-1,sizeof(head));
ll n,q;
cin>>n;
for(ll i=1; i<n; i++)
{
ll u,v;
cin>>u>>v;
add(u,v);
add(v,u);
}
dfs(1,0);
build(1,1,n);
cin>>q;
while(q--)
{
ll x;
cin>>x;
cout<<ask(1,dfn[x],dfn[x]+sizx[x]-1)-(deep[x]-1)*(sizx[x])<<endl;
}
}