这是一道树链剖分的题目;

很容易想到,我们在树剖后,对于操作1,直接单点修改;

对于答案查询,我们直接的时候,我们假设查询的点是3,那么我们在查询的时候可分为两部分;

第一部分:查找出除3这颗子树以外有多少个蘑菇,然后将蘑菇数*此路径;

然后再一一枚举3这颗树的各个子树即可;

这种做法在牛客上能过,不过比赛时的测评应该会超时,比如当出现菊花图的时候,复杂度就会到n^2log n;

先把这份代码贴上:

 #include<bits/stdc++.h>
using namespace std;
const int maxx = 1e6+;
typedef long long LL;
struct node
{
int to,val,next;
}e[maxx*];
int head[maxx],tot=;
int son[maxx],id[maxx],fa[maxx],dep[maxx],siz[maxx],top[maxx],cnt=;
int a[maxx];
LL t[maxx<<],lazy[maxx<<];
int n;
void update(int l,int r,int p,int q,int k,int rt)
{
if(l==r){
t[rt]+=1LL*k;
return;
}
int mid=(l+r)/;
if(p<=mid)update(l,mid,p,q,k,rt*);
else update(mid+,r,p,q,k,rt*+);
t[rt]=t[rt*]+t[rt*+];
}
LL query(int l,int r,int L,int R,int rt)
{
if(L<=l&&R>=r){
return t[rt];
}
int mid=(l+r)/;
LL ans=;
if(L<=mid) ans+=query(l,mid,L,R,rt<<);
if(R>mid) ans+=query(mid+,r,L,R,rt<<|);
return ans;
}
void add(int u,int v,int w)
{
e[++tot].to=v;e[tot].val=w;
e[tot].next=head[u];head[u]=tot;
}
void dfs1(int x,int f,int deep)
{
dep[x]=deep;
fa[x]=f;
siz[x]=;
int maxson=-;
for(int i=head[x];i;i=e[i].next)
{
int y=e[i].to;
if(y==f)continue;
dfs1(y,x,deep+);
a[y]=e[i].val;
siz[x]+=siz[y];
if(siz[y]>maxson)son[x]=y,maxson=siz[y];
}
}
void dfs2(int x,int topf)
{
id[x]=++cnt;
top[x]=topf;
if(!son[x])return;
dfs2(son[x],topf);
for(int i=head[x];i;i=e[i].next)
{
int y=e[i].to;
if(y==fa[x]||y==son[x])continue;
dfs2(y,y);
}
}
void change(int x,int y,int k)
{
while(top[x]!=top[y])
{
if(dep[top[x]]<dep[top[y]])swap(x,y);
// update(1,n,id[top[x]],id[x],k,1);
x=fa[top[x]];
}
if(dep[x]>dep[y])swap(x,y);
// update(1,n,id[x],id[y],k,1);
}
LL getsum(int x)
{
LL ans=;
ans+=(query(,n,id[],id[]+siz[]-,)-query(,n,id[x],id[x]+siz[x]-,))*a[x];
for(int i=head[x];i;i=e[i].next)
{
int y=e[i].to;
if(y==fa[x])continue;
ans+=query(,n,id[y],id[y]+siz[y]-,)*e[i].val;
}
return ans;
}
int main()
{
scanf("%d",&n);
int u,v,w;
for(int i=;i<n;i++){
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);add(v,u,w);
}
dfs1(,,);
dfs2(,);
int q;
scanf("%d",&q);
int op,st=,x,k;
while(q--){
scanf("%d",&op);
if(op==){
scanf("%d%d",&x,&k);
update(,n,id[x],id[x],k,);
// change(1,x,k);
}
else scanf("%d",&st);
printf("%lld\n",getsum(st));
}
return ;
}

那么应该如何优化呢,这就需要充分理解树剖的轻重链;

优化之后的做法分为3部分(需要预处理出目前有多少个蘑菇,已经每个节点有多少个蘑菇)

1.求出某节点的重儿子这棵树有多少个蘑菇,再*上重儿子的权值;

2.求出某节点的轻儿子的最后答案;

3.剩下的蘑菇数就是除这颗树以外的所有蘑菇,我们用总数减去以上两部分,再减去这个节点的蘑菇数(这个节点的蘑菇数贡献为0),得出的数乘上此节点的路径权值即可;

这思路代码我没有自己写,所以贴上某神犇的代码;神犇代码风格与上文略有不同;

我的是单点修改区间查询;

 #include<bits/stdc++.h>
#define rint register int
#define deb(x) cerr<<#x<<" = "<<(x)<<'\n';
#define fi first
#define se second
using namespace std;
typedef long long ll;
using pii = pair <ll,ll>;
const int maxn = 1e6 + ;
int n, q, dep[maxn], fa[maxn], fv[maxn], size[maxn];
ll sum, t[maxn<<], lz[maxn<<], cnt[maxn];
int dfn[maxn], id[maxn], tot, son[maxn], top[maxn];
vector <pii> g[maxn];
pii ans[maxn]; void dfs1(int u, int f, int de) {
dep[u] = de, fa[u] = f, size[u] = ;
for(auto tmp : g[u]) {
int v = tmp.fi;
int w = tmp.se;
if(v == f) continue;
dfs1(v, u, de+);
fv[v] = w;
size[u] += size[v];
if(size[son[u]] < size[v]) son[u] = v;
}
} void dfs2(int u, int tp) {
top[u] = tp, dfn[++tot] = u, id[u] = tot;
if(son[u]) dfs2(son[u], tp);
for(auto tmp : g[u]) {
int v = tmp.fi;
if(v == fa[u]) continue;
if(v == son[u]) continue;
dfs2(v, v);
}
} void pushdown(int rt) {
if(lz[rt]) {
t[rt<<] += lz[rt];
t[rt<<|] += lz[rt];
lz[rt<<] += lz[rt];
lz[rt<<|] += lz[rt];
lz[rt] = ;
}
} void update(ll x, int L, int R, int l, int r, int rt) {
if(l>R || r<L) return;
if(l>=L && r<=R) {
t[rt] += x;
lz[rt] += x;
return;
}
pushdown(rt);
int mid = l + r >> ;
update(x, L, R, l, mid, rt<<);
update(x, L, R, mid+, r, rt<<|);
t[rt] = t[rt<<] + t[rt<<|];
} ll query(int pos, int l, int r, int rt) {
if(pos>r || pos<l) return ;
if(l == r) return t[rt];
pushdown(rt);
int mid = l + r >> ; ll ret = ;
ret += query(pos, l, mid, rt<<);
ret += query(pos, mid+, r, rt<<|);
return ret;
} void gao(int u, int x) {
while(u) {
update(x, id[top[u]], id[u], , n, );
u = top[u];
ans[fa[u]].fi += 1ll * x * fv[u];
ans[fa[u]].se += x;
u = fa[u];
}
} void solve(int u) {
ll res = , num = query(id[son[u]], , n, );
res += 1ll * num * fv[son[u]];
res += 1ll * (sum - cnt[u] - num - ans[u].se) * fv[u];
res += ans[u].fi;
printf("%lld\n", res);
} int main() {
scanf("%d", &n);
for(int i=, u, v, w; i<n; i++) {
scanf("%d%d%d", &u, &v, &w);
g[u].push_back({v, w});
g[v].push_back({u, w});
}
dfs1(, , );
dfs2(, );
scanf("%d", &q);
int op, v, x, rt = ;
while(q--) {
scanf("%d", &op);
if(op == ) {
scanf("%d%d", &v, &x);
sum += x;
cnt[v] += x;
gao(v, x);
} else scanf("%d", &rt);
solve(rt);
}
}

F 采蘑菇的克拉莉丝的更多相关文章

  1. Wannafly Camp 2020 Day 2F 采蘑菇的克拉莉丝 - 树链剖分

    如果暴力维护,每次询问时需要对所有孩子做计算 考虑通过树剖来平衡修改与询问的时间,询问时计算重链和父树,轻链的贡献预先维护好,修改时则需要修改可能影响的轻链贡献,因为某个点到根的路径上轻重交替只有 \ ...

  2. 洛谷——P2656 采蘑菇

    P2656 采蘑菇 题目描述 小胖和ZYR要去ESQMS森林采蘑菇. ESQMS森林间有N个小树丛,M条小径,每条小径都是单向的,连接两个小树丛,上面都有一定数量的蘑菇.小胖和ZYR经过某条小径一次, ...

  3. [Luogu 2656] 采蘑菇

    Description 小胖和ZYR要去ESQMS森林采蘑菇. ESQMS森林间有N个小树丛,M条小径,每条小径都是单向的,连接两个小树丛,上面都有一定数量的蘑菇.小胖和ZYR经过某条小径一次,可以采 ...

  4. 【Foreign】采蘑菇 [点分治]

    采蘑菇 Time Limit: 20 Sec  Memory Limit: 256 MB Description Input Output Sample Input 5 1 2 3 2 3 1 2 1 ...

  5. 洛谷—— P2656 采蘑菇

    https://www.luogu.org/problem/show?pid=2656 题目描述 小胖和ZYR要去ESQMS森林采蘑菇. ESQMS森林间有N个小树丛,M条小径,每条小径都是单向的,连 ...

  6. 【细节题 离线 树状数组】luoguP4919 Marisa采蘑菇

    歧义差评:但是和题意理解一样了之后细节依然处理了很久,说明还是水平不够…… 题目描述 Marisa来到了森林之中,看到了一排nn个五颜六色的蘑菇,编号从1-n1−n,这些蘑菇的颜色分别为col[1], ...

  7. Luogu P2656 采蘑菇

    尽管是缩点的习题,思路也是在看了题解后才明白的. 首先,每个强连通分量内的点都是一定互通的,也就是可以完全把这里面的边都跑满,摘掉所有能摘的蘑菇.那么,考虑给每一个强连通分量化为的新点一个点权,代表摘 ...

  8. [Luogu1119]采蘑菇

    题目大意: 给你一个无向图,点i在时间t[i]之前是不存在的,有q组询问,问你时间为t时从x到y的最短路. 点的编号按出现的时间顺序给出,询问也按照时间顺序给出. 思路: Floyd. Floyd的本 ...

  9. [Luogu2656]采蘑菇

    题目大意: 给你一个有向图,每条边有一个边权w以及恢复系数k, 你从s点出发乱走,经过某条边时会获得相应的收益w,而当第二次经过这条边时相应的收益为w*k下取整. 问你最大能获得的收益为多少? 思路: ...

随机推荐

  1. Blazor client-side Preview 预览版 如何调试 Debug

    首先我们使用最简单的模板案例,里面有一个Counter计数器,你可以在创建模板中找到. 首先需要设置运行调试方式为IIS Express.这意味着,MAC可能不能使用调试. 然后开启运行而不调试(Ct ...

  2. PMP--2.2 效益管理计划

    一.文件背景概述 ​​​1. 所需文件/数据 制定效益管理计划需要使用商业论证和需求评估中的数据和信息,例如,成本效益分析数据. 成本效益分析数据是在商业论证和需求评估中得到的,在成本效益分析中已经把 ...

  3. Vue中使用NProgress实现进度条

    简介 NProgress是页面跳转或者发生异步请求是浏览器顶部的进度条 GitHub地址:https://github.com/rstacruz/nprogress 在线演示地址:http://ric ...

  4. mysql 查询出现 "this is incompatible with sql_mode=only_full_group_by"错误解决方案,以及个人rpm方式重装所遇到的问题备份

    一.错误说明        这个错误发生在mysql 5.7 版本及以上版本会出现的问题:        mysql .7版本默认的sql配置是:sql_mode="ONLY_FULL_GR ...

  5. go 序列化

    序列化 package main import ( "encoding/json" "fmt" ) //结构体 type Monster struct { Na ...

  6. c#winform自定义窗体,重绘标题栏,自定义控件学习

    c#winform自定义窗体,重绘标题栏 虽然现在都在说winform窗体太丑了,但是我也能尽量让桌面应用程序漂亮那么一点点话不多说,先上图 重绘标题栏先将原生窗体设置成无边框,FormBoderSt ...

  7. gcc 与g++

    which gcc     查看gcc           主要针对 .c which g++    查看g++            主要针对  .cpp yum install gcc  安装gc ...

  8. 【剑指Offer】61、把二叉树打印成多行

    题目描述 从上到下按层打印二叉树,同一层结点从左至右输出.每一层输出一行. 题解一:BFS public static ArrayList<ArrayList<Integer>> ...

  9. Win10的Cortana小娜反应慢?试试这个方法

    https://www.ithome.com/html/win10/158466.htm Win10语音助手Cortana小娜可以为用户提供全面的搜索服务,不管是本地还是在线,都可以轻松找到结果.不过 ...

  10. learn to rank 模型概述

    模型总体描述: https://zhuanlan.zhihu.com/p/26539920 LambdaMART中Lambda计算以及RegressionTree训练: https://blog.cs ...