中北大学 tag日常:(dfs序+线段树)

传送门:

这题我想到了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;
    }
}
发布了254 篇原创文章 · 获赞 25 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/yangzijiangac/article/details/104461186