AT_abc187_e
考虑将 \(1\) 号点定为树根,然后通过搜索确定结点之间的父子关系。对于每次操作,先判断该边两端的点的父子关系,然后再分类讨论进行操作。
如何维护每个点的点权呢?注意到,修改有很多次,但查询只在最后有一次,因此可以考虑树上差分。具体地,设 \(a_i\) 表示 \(i\) 的点权,\(f_i\) 表示 \(i\) 的父亲,\(sum_i\) 表示 \(a_i\) 与 \(a_{f_i}\) 的差,对每次操作进行分类讨论。
假设选定边连接的点分别为 \(u\) 和 \(v\),且 \(f_v=u\),则有如下情况:
-
从 \(v\) 出发。等同于给以 \(v\) 为根的子树的每个点点权加上 \(k\),将 \(sum_v\) 加上 \(k\) 即可。
-
从 \(u\) 出发。等同于给除以 \(v\) 为根的子树外的每个点点权加上 \(k\),也可理解为全部点点权加上 \(k\),再给以 \(v\) 为根的子树的每个点点权减去 \(k\)(相当于没有操作,符合要求)。将 \(sum_1\) 加上 \(k\),\(sum_v\) 减去 \(k\) 即可。
完成全部操作后,再进行一次搜索,通过差分数组求出每个点的点权,输出答案。
时间复杂度 \(O(n+q)\),代码如下:
#include <iostream>
#include <cstdio>
#include <vector>
#define int long long
#define N 1000001
using namespace std;
vector<int> G[N];
int n,m,fa[N],t,nw,k,u[N],v[N],sum[N],ans[N],tot;
void dfs( int nowu )
{
for( int i = 0 ; i < G[nowu].size() ; i ++ )
{
int nowv = G[nowu][i];
if( !fa[nowv] )
{
fa[nowv] = nowu;
dfs( nowv );
}
}
}
void dfsans( int nowu , int s )
{
ans[nowu] += s;
for( int i = 0 ; i < G[nowu].size() ; i ++ )
{
int nowv = G[nowu][i];
if( fa[nowv] == nowu )
dfsans( nowv , s + sum[nowv] );
}
}
signed main()
{
int T;
cin >> n;
m = n - 1;
for( int i = 1 ; i <= m ; i ++ )
{
cin >> u[i] >> v[i];
G[u[i]].push_back( v[i] );
G[v[i]].push_back( u[i] );
}
fa[1] = 1;
dfs( 1 );
cin >> T;
while( T -- )
{
cin >> t >> nw >> k;
if( t == 1 )
{
if( fa[u[nw]] == v[nw] ) sum[u[nw]] += k;
else
{
sum[1] += k;
sum[v[nw]] -= k;
}
}
else
{
if( fa[v[nw]] == u[nw] ) sum[v[nw]] += k;
else
{
sum[1] += k;
sum[u[nw]] -= k;
}
}
}
dfsans( 1 , sum[1] );
for( int i = 1 ; i <= n ; i ++ )
cout << ans[i] << endl;
return 0;
}
还是菜。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现