当前位置:网站首页>[2020WC Day2]F.采蘑菇的克拉莉丝(子树和查询、轻重儿子思想)
[2020WC Day2]F.采蘑菇的克拉莉丝(子树和查询、轻重儿子思想)
2022-04-23 06:21:00 【Zimba_】
题意:
给定一棵 n n n个点, n − 1 n-1 n−1条边的带边权的无向图,图上的点可以长蘑菇。克拉莉丝起始点在点 1 1 1。
接着发生 q q q次事件。事件有两种:
- 1 v x 1\;v\;x 1vx表示在点 v v v上新长了 x x x个蘑菇。
- 2 v 2\;v 2v表示克拉莉丝的起始位置变成了点 v v v。
在每个事件后,克拉莉丝想要知道她收集完所有蘑菇的代价。
对于任意一个蘑菇,收集它的代价是这个蘑菇所在点到克拉莉丝起始点路径上最靠近克拉莉丝起始点的边的边权。
数据范围: 1 ≤ n ≤ 1 0 6 1\leq n\leq 10^{6} 1≤n≤106, 1 ≤ q ≤ 1 0 6 1\leq q\leq 10^{6} 1≤q≤106
思路:
我们把起点的代价贡献分为三类求,连父亲的边,连重儿子的边,连轻儿子的边。
考虑其中某个点作为起点,与父亲连的边的贡献次数是除了这个点子树以外其他点的蘑菇总数。这个我们只需要能处理子树和查询(dfs序+树状数组)就行了,然后贡献次数就是根的子树和减去这个点的子树和。
然后考虑重儿子的边的贡献次数,就是重儿子的子树和。
最后是轻儿子的贡献,由于轻儿子比较多,我们没办法去枚举。我们考虑在一个轻儿子上加蘑菇时,就暴力跳轻边,把贡献加在跳到的每个点上。这样跳的次数是 l o g n logn logn的。
最后复杂度就是 o ( n l o g n ) o(nlogn) o(nlogn)。
代码:
改天再写。
(upd:修复了轻边跳到重边为止的bug,对于重链我们维护一个top数组记链头,可以直接跳过重链)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 1000000;
ll c[1000005];
void add(ll x,ll k) {
while(x<=N) {
c[x]+=k;
x+=x&-x;
}
}
ll getSum(ll x) {
ll res=0;
while(x>0) {
res+=c[x];
x-=x&-x;
} return res;
}
ll val[1000005],sum[1000005];
ll fa[1000005],siz[1000005],son[1000005];
vector<ll>v[1000005],g[1000005];
ll id[1000005],idd;
void dfs(ll x,ll pre)
{
id[x]=++idd;
fa[x]=pre;
siz[x]=1;
for(ll i=0;i<v[x].size();i++)
{
ll to=v[x][i],w=g[x][i];
if(to!=pre)
{
dfs(to,x);
val[to]=w;
siz[x]+=siz[to];
}
}
for(ll to:v[x])if(to!=pre)
{
if(son[x]==0||siz[to]>siz[son[x]])son[x]=to;
}
}
ll top[1000005];
void dfstop(ll x,ll pre)
{
if(son[pre]==x)top[x]=top[pre];
else top[x]=x;
for(ll i=0;i<v[x].size();i++)
{
ll to=v[x][i];
if(to!=pre)
{
dfstop(to,x);
}
}
}
int main()
{
ll n;
scanf("%lld",&n);
for(ll i=1;i<n;i++)
{
ll a,b,w;
scanf("%lld%lld%lld",&a,&b,&w);
v[a].push_back(b);
v[b].push_back(a);
g[a].push_back(w);
g[b].push_back(w);
}
dfs(1,0);
dfstop(1,0);
ll q;
scanf("%lld",&q);
int now=1;
while(q--)
{
ll opt;
scanf("%lld",&opt);
if(opt==1)
{
ll v,x;
scanf("%lld%lld",&v,&x);
add(id[v],x);
while(v!=0)
{
sum[fa[top[v]]]+=x*val[v];
v=fa[top[v]];
}
}
else
{
ll v;
scanf("%lld",&v);
now=v;
}
ll ans=val[now]*(getSum(n)-(getSum(id[now]+siz[now]-1)-getSum(id[now]-1)))+val[son[now]]*(getSum(id[son[now]]+siz[son[now]]-1)-getSum(id[son[now]]-1))+sum[now];
printf("%lld\n",ans);
}
return 0;
}
/* 6 1 2 1 1 4 1 2 3 1 4 5 1 5 6 1 1 1 3 1 */
版权声明
本文为[Zimba_]所创,转载请带上原文链接,感谢
https://blog.csdn.net/weixin_43785386/article/details/109960141
边栏推荐
猜你喜欢
随机推荐
特殊成员与魔法方法
Beifeng communication helps Zhanjiang fire brigade build PDT wireless communication system
字节跳动2020秋招编程题:根据工号快速找到自己的排名
PyTorch 19. Differences and relations of similar operations in pytorch
连接orcale
自定义classloader并实现热部署-使用loadClass
How to improve the service efficiency of the hotel without blind spots and long endurance | public and Private Integrated walkie talkie?
Jupyter Notebook 安装
小程序wx.previewMedia相关问题解决-日常踩坑
ESP32学习-GPIO的使用与配置
Emergency communication system for flood control and disaster relief
启动mqbroker.cmd失败解决方法
PC端一次启动多个微信
获取字符格式的当前时间
JDBC连接池
浅谈BFC(块格式化上下文)
应急医疗通讯解决方案|MESH无线自组网系统
小程序换行符\n失效问题解决-日常踩坑
What is a closure?
el-table的数据更新后,页面中数据未更新this.$forceUpdate()无效果