竞赛讨论区 > F dfs序+线段树
头像
BlessingNow
发布于 2024-11-13 09:30 陕西
+ 关注

F dfs序+线段树

首先dfs求出:

dep:每个节点深度

siz:每个节点子树大小

dfn:每个节点的dfs序

val:每个节点到根节点的路径和

一个节点u往下d次的最大边权和,就是找深度为dep[u] + d的点中,在u的子树中的,最大的val[i]。然后再减去val[u]。

判断是否在u的子树中,即判断节点的dfs序是否属于$[dfn[u],dfn[u]+siz[u]-1]$。如果对每个深度开一个线段树,那就是一个单点修改+区间查询最大值。

#include<bits/stdc++.h>


using namespace std;
using ll = long long;
using pii = pair<int,int>;
using pll = pair<ll,ll>;

int n,q;
vector<vector<pll>> g;

const int N = 5e6+10;
const int M = 1e5+10;
ll maxv[N],ls[N],rs[N],rt[2*M],cnt;
ll val[M];//根节点到该点的权值和
int dfn[M],rnk[M];
int dep[M],siz[M];

void dfs(int u,int fa){
    dfn[u] = ++*dfn;
    rnk[dfn[u]] = u;
    siz[u] = 1;
    for(auto [v,w]:g[u]){
        if(v==fa) continue;
        dep[v] = dep[u]+1;
        val[v] = val[u]+w;
        dfs(v,u);
        siz[u] += siz[v];
    } 
}

void pushup(int u){
    maxv[u] = max(maxv[ls[u]],maxv[rs[u]]);
}
ll modify(int u,int l,int r,int co,ll val){
    if(!u) u = ++ cnt;
    if(l==r){
        maxv[u] = max(maxv[u],val);
        return u;
    }
    int mid = l+r>>1;
    if(co<=mid){
        ls[u] = modify(ls[u],l,mid,co,val);
    }
    else{
        rs[u] = modify(rs[u],mid+1,r,co,val);
    }
    pushup(u);
    return u;
}
ll query(int u,int l,int r,int x,int y){
    if(!u) return -1e9;
    if(x>r || y<l) return -1e9;
    if(x<=l && y>=r) return maxv[u];
    int mid = l+r>>1;
    return max(query(ls[u],l,mid,x,y),query(rs[u],mid+1,r,x,y));
}

void solve(){
    cin>>n;
    g = vector<vector<pll>>(n+1);
    for(int i=1;i<n;i++){
        int u,v,w;
        cin>>u>>v>>w;
        g[u].push_back({v,w});
        g[v].push_back({u,w});
    }
    dep[1] = 1;
    dfs(1,0);
    for(int i=1;i<=n;i++){
        rt[dep[i]] = modify(rt[dep[i]],1,n,dfn[i],val[i]);
    }
    int q;
    cin>>q;
    while(q--){
        int u,d; cin>>u>>d;
        ll ans = query(rt[dep[u] + d],1,n,dfn[u],dfn[u]+siz[u]-1);
        if(ans<=0) cout<<-1<<endl;
        else{
            cout<<ans - val[u]<<endl;
        }
    }
}

int main(){		
#ifdef LOCAL
	freopen("in.txt", "r", stdin);
	freopen("output.txt", "w", stdout);
#endif
	std::ios::sync_with_stdio(0);std::cout.tie(0);std::cin.tie(0);
	int T = 1;
#ifdef MULTI_TEST
	cin>>T;
#endif
	while(T--){
		solve();
	}
	return 0;
}

`

全部评论

(0) 回帖
加载中...
话题 回帖

等你来战

查看全部

热门推荐