• Codeforces 739B Alyona and a tree(树上路径倍增及差分)


    题目链接 Alyona and a tree

    比较考验我思维的一道好题。

    首先,做一遍DFS预处理出$t[i][j]$和$d[i][j]$。$t[i][j]$表示从第$i$个节点到离他第$2^{j}$近的祖先,$d[i][j]$表示从$i$开始到$t[i][j]$的路径上的路径权值总和。

    在第一次DFS的同时,对节点$x$进行定位(结果为$dist(x, y)<=a(y)$)的离$x$最远的$x$的某个祖先,然后进行$O(1)$的差分。

    第一次DFS完成后,做第二次DFS统计答案(统计差分后的结果)

    时间复杂度$O(NlogN)$

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define REP(i, n)		for(int i(0); i <  (n); ++i)
    #define rep(i, a, b)		for(int i(a); i <= (b); ++i)
    #define dec(i, a, b)		for(int i(a); i >= (b); --i)
    #define LL      		long long
    #define sz(x)			(int)x.size()
    
    const int N     =    200000      +       10;
    const int A     =    30          +       1;
    
    vector <int> v[N], c[N];
    LL a[N], deep[N];
    LL x, y;
    int n, cnt;
    LL t[N][A], d[N][A];
    LL g[N], value[N];
    LL s[N];
    LL ans[N];
    
    void dfs(int x, int fa){
    
    	if (g[x]){
    		t[x][0] = g[x];
    		d[x][0] = value[x];
    		for (int i = 0; t[t[x][i]][i]; ++i){
    			t[x][i + 1] = t[t[x][i]][i];
    			d[x][i + 1] = d[t[x][i]][i] + d[x][i];
    		}
    		int now = x, noww = 0;
    		bool flag = false;
    		dec(i, 20, 0){
    			if (t[now][i] && d[now][i] + noww <= a[x]){
    				noww += d[now][i];
    				now = t[now][i];
    				flag = true;
    			}
    		}
    		if (flag){
    			--s[g[now]]; ++s[g[x]];
    		}
    	}
    
    	REP(i, sz(v[x])){
    		int u = v[x][i];
    		deep[u] = deep[x] + 1;
    		dfs(u, x);
    	}
    }
    
    void dfs2(int x){
    	ans[x] += s[x];
    	REP(i, sz(v[x])){
    		dfs2(v[x][i]);
    		ans[x] += ans[v[x][i]];
    	}
    }
    
    int main(){
    
    	scanf("%d", &n);
    	rep(i, 1, n) scanf("%lld", a + i);
    	rep(i, 2, n){
    		scanf("%lld%lld", &x, &y);
    		g[i] = x; value[i] = y;
    		v[x].push_back(i), c[x].push_back(y);
    	}
    
    	memset(s, 0, sizeof s);
    	cnt = 0;
    	deep[1] = 0;
    	dfs(1, 0);
    	memset(ans, 0, sizeof ans);
    	dfs2(1);
    	rep(i, 1, n - 1) printf("%lld ", ans[i]);
    	printf("%lld
    ", ans[n]);
    	return 0;
    
    }
    
    
    




  • 相关阅读:
    C# Socket编程
    C# Socket编程
    Android基础入门教程
    Android基础入门教程
    SQL Server查询事务
    SQL Server查询事务
    SQL事务用法begin tran,commit tran和rollback tran的用法
    SQL事务用法begin tran,commit tran和rollback tran的用法
    SQL Server Insert操作中的锁
    SQL Server Insert操作中的锁
  • 原文地址:https://www.cnblogs.com/cxhscst2/p/6648800.html
Copyright © 2020-2023  润新知