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

很容易想到,我们在树剖后,对于操作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. C#基础知识学习(2)string类中的方法

    1.Compare 比较字符串 用来比较2个字符串的长度大小和值是否相同,相同则返回0,当x比y小返回-1,否则返回1,如果长度相同,且值不同,则返回1,代码如下 public static void ...

  2. Hibernate入门之创建数据库表

    前言 Hibernate 5.1和更早版本至少需要Java 1.6和JDBC 4.0,Hibernate 5.2和更高版本至少需要Java 1.8和JDBC 4.2,从本节开始我们正式进入Hibern ...

  3. clr via c# clr寄宿和AppDomain (一)

    1 clr寄宿-----.net framework在windows平台的顶部允许.者意味着.net framework必须用windows能理解的技术来构建.所有托管模块和程序集文件必须使用wind ...

  4. Cesium案例解析(六)——3DTilesInspector监视器

    目录 1. 概述 2. 案例 1. 概述 3D Tiles作为传输和渲染大规模3D地理空间数据的格式,应对的都是大规模数据的场景,Cesium提供了一个监视3D Tiles数据的监视器,可以通过这个监 ...

  5. redis 5.0.7 源码阅读——跳跃表skiplist

    redis中并没有专门给跳跃表两个文件.在5.0.7的版本中,结构体的声明与定义.接口的声明在server.h中,接口的定义在t_zset.c中,所有开头为zsl的函数. 一.数据结构 单个节点: t ...

  6. clr via c# 泛型

    1,类型对象,对于应用程序的各种类型创建的对象叫做类型对象:Type object:对于泛型类型参数的类型,CLR同样也会创建内部类型对象,适用于 引用类型 值类型 接口类型 委托类型 具有泛型类型参 ...

  7. 并查集find,merge操作

    一.find操作 //find操作路径压缩版 inline int find(int x){ if(fa[x]==x) return x; int t=find(fa[x]); fa[x]=t; re ...

  8. python——面向对象(1),基础

    """面向对象:抽象化编程思想.类,对象:用类来创建(实例化)对象.类:一系列特征和行为相同的事物总和, 1.属性:特征 2.行为:方法 定义类 :PEP 8要求标识符的 ...

  9. 从 0 使用 SpringBoot MyBatis MySQL Redis Elasticsearch打造企业级 RESTful API 项目实战

    大家好!这是一门付费视频课程.新课优惠价 699 元,折合每小时 9 元左右,需要朋友的联系爱学啊客服 QQ:3469271680:我们每课程是明码标价的,因为如果售价为现在的 2 倍,然后打 5 折 ...

  10. Umi 小白纪实(一)—— 创建项目&常用配置

    umi 是一个企业级 react 应用框架,也是蚂蚁金服的底层前端框架 <蚂蚁金服的前端框架和工程化实践> 一.安装脚手架 在创建项目之前,需要保证有 node 8.10 以上的环境 可以 ...