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

很容易想到,我们在树剖后,对于操作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. Linux运维---1.Ceph分布式存储架构及工作原理

    Ceph理论 Ceph 简介 Ceph 是一个开源项目,它提供软件定义的.统一的存储解决方案 .Ceph 是一个具有高性能.高度可伸缩性.可大规模扩展并且无单点故障的分布式存储系统 . Ceph 是软 ...

  2. C# 利用委托事件进行窗体间的传值(新手必看)

    引言: 窗体间传值是每个学习WinForm新手的常见问题,最初级的方法就是 在窗体中先获取到要接受值窗体.然后通过.得到某个空间或者属性,直接赋值,这个需要接收放的窗体属性或者空间必须是public ...

  3. Java基础之六、Java编程思想(8-10)

    八.多态 多态(也称作动态绑定.后期绑定或运行时绑定) 域(成员变量)是不具有多态性的,只有普通的方法调用是多态的,任何域访问操作都将由编译器解析,因此不是多态的 静态方法也是不具有多态性的 publ ...

  4. JS正则表达式的创建、匹配字符串、转义、字符类、重复以及常用字符

    正则表达式都是操作字符串的 作用:对数据进行查找.替换.有效性验证 创建正则表达式的两种方式: // 字面量方式 /js/ // 构造函数方式 regular expression new RegEx ...

  5. 一行代码解决MacBook Pro安装VSCode没有应用图标问题

    笔者今天升级了VSCode,安装完后发现Dock(程序坞)没有VSCode的图标了,导致切换应用非常不方便. 具体情况就像下面这张图,VSCode明明开着,但是在Dock找不到VSCode了. 解决办 ...

  6. 阿里妈妈的iconfont的引用问题

    一.先进官网 我们看到了上面的这些图标,是不是很心动,阿里妈妈就是给力,给马老师点赞,但是问题来了我们怎么去使用呢. 二.点击图标 嘿嘿,上面的操作步骤我就不多说了吧,我相信大家都会做的,接下来我们就 ...

  7. Java源码系列2——HashMap

    HashMap 的源码很多也很复杂,本文只是摘取简单常用的部分代码进行分析.能力有限,欢迎指正. HASH 值的计算 前置知识--位运算 按位异或操作符^:1^1=0, 0^0=0, 1^0=0, 值 ...

  8. Go 与 PHP 的语法对比

    Go 是由 Google 设计的一门静态类型的编译型语言.它有点类似于 C,但是它包含了更多的优点,比如垃圾回收.内存安全.结构类型和并发性.它的并发机制使多核和网络机器能够发挥最大的作用.这是 Go ...

  9. 41.Python中加载静态文件

    在一个网页中,不仅仅只有一个html骨架,还需要css样式文件,js执行文件以及一些图片等.因此在DTL中加载静态文件时一个必须要解决的问题.在DTL中,使用static标签来加载静态文件.要使用st ...

  10. 我眼中的ASP.NET.MVC

    MVC MVC全名 : Model View Controller ( Model-模型 View-视图  Controller-控制器)是一种经典的,经久不衰的,屹立不倒的软件设计框架.实现了业务逻 ...