1 条题解

  • 0
    @ 2026-4-26 15:54:31

    思路:

    简单题,考虑势能,由于技能值只增不减,所以若现在能在这个地方卖出糖果,则以后肯定也可以。

    故问题相当于:

    • 每个点初始权值为 wu=0w_u = 0

    • 子树权值加。

    • 显然一个点能卖出糖果当且仅当 wulimuw_u \ge lim_u;询问一条从根出发的路径中能卖出糖果的点的数量的最大值。

    考虑线段树快速找到最新 wulimuw_u \ge lim_u 的点,即初始权值为 limu-lim_u,维护区间最大值,支持区间加,若 0\ge 0 了则往下找;找到后赋值为 inf-\inf

    考虑若一个点 uu 能卖出糖果对答案的贡献,显然到 uu 子树内的点的答案都会增加一。

    故维护两个线段树,一个维护势能找最新可以卖糖果的点,一个用来维护答案。

    时间复杂度为 O(NlogN)O(N \log N)

    完整代码:

     #include<bits/stdc++.h>
    #define lowbit(x) x & (-x)
    #define ls(k) k << 1
    #define rs(k) k << 1 | 1
    #define fi first
    #define se second
    #define ctz(x) __builtin_ctz(x)
    #define popcnt(x) __builtin_popcount(x)
    #define open(s1, s2) freopen(s1, "r", stdin), freopen(s2, "w", stdout);
    using namespace std;
    typedef __int128 __;
    typedef long double lb;
    typedef double db;
    typedef unsigned long long ull;
    typedef long long ll;
    bool Begin;
    const int N = 5e5 + 10;
    inline ll read(){
        ll x = 0, f = 1;
        char c = getchar();
        while(c < '0' || c > '9'){
            if(c == '-')
              f = -1;
            c = getchar();
        }
        while(c >= '0' && c <= '9'){
            x = (x << 1) + (x << 3) + (c ^ 48);
            c = getchar();
        }
        return x * f;
    }
    inline void write(ll x){
    	if(x < 0){
    		putchar('-');
    		x = -x;
    	}
    	if(x > 9)
    	  write(x / 10);
    	putchar(x % 10 + '0');
    }
    int n, q, u, x, cnt;
    int fa[N], id[N], siz[N], dfn[N];
    ll lim[N];
    vector<int> E[N];
    inline void dfs(int u){
    	siz[u] = 1;
    	dfn[u] = ++cnt;
    	id[cnt] = u;
    	for(auto v : E[u]){
    		dfs(v);
    		siz[u] += siz[v];
    	}
    }
    namespace Seg{
    	struct Node{
    		int l, r;
    		int Max, tag;
    	}X[N << 2];
    	inline void pushup(int k){
    		X[k].Max = max(X[k << 1].Max, X[k << 1 | 1].Max);
    	}
    	inline void add(int k, int v){
    		X[k].Max += v;
    		X[k].tag += v;
    	}
    	inline void push_down(int k){
    		if(X[k].tag){
    			add(k << 1, X[k].tag);
    			add(k << 1 | 1, X[k].tag);
    			X[k].tag = 0;
    		}
    	}
    	inline void build(int k, int l, int r){
    		X[k].l = l, X[k].r = r;
    		if(l == r)
    		  return ;
    		int mid = (l + r) >> 1;
    		build(k << 1, l, mid);
    		build(k << 1 | 1, mid + 1, r);
    	}
    	inline void update(int k, int l, int r, int v){
    		if(X[k].l == l && r == X[k].r){
    			add(k, v);
    			return ;
    		}
    		push_down(k);
    		int mid = (X[k].l + X[k].r) >> 1;
    		if(r <= mid)
    		  update(k << 1, l, r, v);
    		else if(l > mid)
    		  update(k << 1 | 1, l, r, v);
    		else{
    			update(k << 1, l, mid, v);
    			update(k << 1 | 1, mid + 1, r, v); 
    		}
    		pushup(k);
    	}
    	inline int getmax(){
    		return X[1].Max;
    	}
    }
    inline void Add(int u, int v){
    	Seg::update(1, dfn[u], dfn[u] + siz[u] - 1, v);
    }
    namespace Tree{
    	struct Node{
    		int l, r;
    		ll Max, tag;
    	}X[N << 2];
    	inline void pushup(int k){
    		X[k].Max = max(X[k << 1].Max, X[k << 1 | 1].Max);
    	}
    	inline void add(int k, int v){
    		X[k].Max += v;
    		X[k].tag += v;
    	}
    	inline void push_down(int k){
    		if(X[k].tag){
    			add(k << 1, X[k].tag);
    			add(k << 1 | 1, X[k].tag);
    			X[k].tag = 0;
    		}
    	}
    	inline void build(int k, int l, int r){
    		X[k].l = l, X[k].r = r;
    		if(l == r){
    			X[k].Max = -lim[id[l]];
    			return ;
    		}
    		int mid = (l + r) >> 1;
    		build(k << 1, l, mid);
    		build(k << 1 | 1, mid + 1, r);
    		pushup(k);
    	}
    	inline void update(int k, int l, int r, int v){
    		if(l > r)
    		  return ;
    		if(X[k].l == l && r == X[k].r){
    			add(k, v);
    			return ;
    		}
    		push_down(k);
    		int mid = (X[k].l + X[k].r) >> 1;
    		if(r <= mid)
    		  update(k << 1, l, r, v);
    		else if(l > mid)
    		  update(k << 1 | 1, l, r, v);
    		else{
    			update(k << 1, l, mid, v);
    			update(k << 1 | 1, mid + 1, r, v); 
    		}
    		pushup(k);
    	}
    	inline void find(int k){
    		if(X[k].Max < 0)
    		  return ;
    		if(X[k].l == X[k].r){
    			Add(id[X[k].l], 1);
    			X[k].Max = LONG_LONG_MIN;
    			return ;
    		}
    		push_down(k);
    		find(k << 1), find(k << 1 | 1);
    		pushup(k);
    	}
    };
    bool End;
    int main(){
    	n = read(), q = read();
    	for(int i = 2; i <= n; ++i){
    		fa[i] = read();
    		E[fa[i]].push_back(i);
    	}
    	for(int i = 1; i <= n; ++i)
    	  lim[i] = read();
    	dfs(1);
    	Seg::build(1, 1, n), Tree::build(1, 1, n);
    	while(q--){
    		u = read(), x = read();
    		Tree::update(1, dfn[u], dfn[u] + siz[u] - 1, x);
    		Tree::find(1);
    		write(Seg::getmax());
    		putchar('\n'); 
    	}
    	cerr << '\n' << abs(&Begin - &End) / 1048576 << "MB";
    	return 0;
    }
    
    • 1

    信息

    ID
    10932
    时间
    3000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    2
    已通过
    1
    上传者