F 采蘑菇的克拉莉丝
这是一道树链剖分的题目;
很容易想到,我们在树剖后,对于操作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 采蘑菇的克拉莉丝的更多相关文章
- Wannafly Camp 2020 Day 2F 采蘑菇的克拉莉丝 - 树链剖分
如果暴力维护,每次询问时需要对所有孩子做计算 考虑通过树剖来平衡修改与询问的时间,询问时计算重链和父树,轻链的贡献预先维护好,修改时则需要修改可能影响的轻链贡献,因为某个点到根的路径上轻重交替只有 \ ...
- 洛谷——P2656 采蘑菇
P2656 采蘑菇 题目描述 小胖和ZYR要去ESQMS森林采蘑菇. ESQMS森林间有N个小树丛,M条小径,每条小径都是单向的,连接两个小树丛,上面都有一定数量的蘑菇.小胖和ZYR经过某条小径一次, ...
- [Luogu 2656] 采蘑菇
Description 小胖和ZYR要去ESQMS森林采蘑菇. ESQMS森林间有N个小树丛,M条小径,每条小径都是单向的,连接两个小树丛,上面都有一定数量的蘑菇.小胖和ZYR经过某条小径一次,可以采 ...
- 【Foreign】采蘑菇 [点分治]
采蘑菇 Time Limit: 20 Sec Memory Limit: 256 MB Description Input Output Sample Input 5 1 2 3 2 3 1 2 1 ...
- 洛谷—— P2656 采蘑菇
https://www.luogu.org/problem/show?pid=2656 题目描述 小胖和ZYR要去ESQMS森林采蘑菇. ESQMS森林间有N个小树丛,M条小径,每条小径都是单向的,连 ...
- 【细节题 离线 树状数组】luoguP4919 Marisa采蘑菇
歧义差评:但是和题意理解一样了之后细节依然处理了很久,说明还是水平不够…… 题目描述 Marisa来到了森林之中,看到了一排nn个五颜六色的蘑菇,编号从1-n1−n,这些蘑菇的颜色分别为col[1], ...
- Luogu P2656 采蘑菇
尽管是缩点的习题,思路也是在看了题解后才明白的. 首先,每个强连通分量内的点都是一定互通的,也就是可以完全把这里面的边都跑满,摘掉所有能摘的蘑菇.那么,考虑给每一个强连通分量化为的新点一个点权,代表摘 ...
- [Luogu1119]采蘑菇
题目大意: 给你一个无向图,点i在时间t[i]之前是不存在的,有q组询问,问你时间为t时从x到y的最短路. 点的编号按出现的时间顺序给出,询问也按照时间顺序给出. 思路: Floyd. Floyd的本 ...
- [Luogu2656]采蘑菇
题目大意: 给你一个有向图,每条边有一个边权w以及恢复系数k, 你从s点出发乱走,经过某条边时会获得相应的收益w,而当第二次经过这条边时相应的收益为w*k下取整. 问你最大能获得的收益为多少? 思路: ...
随机推荐
- 小白学 Python 数据分析(8):Pandas (七)数据预处理
人生苦短,我用 Python 前文传送门: 小白学 Python 数据分析(1):数据分析基础 小白学 Python 数据分析(2):Pandas (一)概述 小白学 Python 数据分析(3):P ...
- linux--解决celery消息中间件带来的一系列问题
启动celery定时任务 1.celery -A OpsManage beat -l info -S django 2.celery -A OpsManage worker -l info 此时消息中 ...
- 多线程笔记 - provider-consumer
通过多线程实现一个简单的生产者-消费者案例(笔记). 首先定义一个要生产消费的数据类 : public class Data { private String id; private String n ...
- MySQL中的执行计划explain
一.用法及定义: explain为sql的执行计划.在sql前面加上explain关键字即可 如:explain select * from tbl_emp; 名词解释: id:[操作表的顺序] 1. ...
- 大厂面试必问题!HashMap 怎样解决hash桶碰撞?
HashMap冲突解决方法比较考验一个开发者解决问题的能力.下文给出HashMap冲突的解决方法以及原理分析,无论是在面试问答或者实际使用中,应该都会有所帮助.在Java编程语言中,最基本的结构就是两 ...
- JS高阶编程技巧--柯理化函数
首先看一段代码: let obj = { x: 100 }; function fn(y) { this.x += y; console.log(this); } 现在有一个需求:在1秒后,执行函数f ...
- Oracle实例占用超高CPU排查
CPU主要功能:处理指令.执行操作.要求进行动作.控制时间.处理数据. 结合数据库实例CPU占用高,可能的原因是数据库在执行大量的操作(全表查询.大量排序等). 由于公司没有DBA,遇到数据库问题只能 ...
- RHEL7开机不能正常进入系统(图形化界面)
今天在重启RHEL7的虚拟机后一直无法正常开机,一直提示输入管理员密码,如下图所示: 输入密码后进入命令行模式,经排查出现此现象的问题是在挂载银盘的时候文件格式写错,在格式化硬盘的时候格式化的是xfs ...
- 记录zabbix4.0升级4.2
系统环境 [root@localhost ~]# cat /etc/redhat-release CentOS release 6.9 (Final) 官方网站 官方文档升级其实很简单如果 ...
- opencv中的图像矩(空间矩,中心矩,归一化中心矩,Hu矩)
严格来讲矩是概率与统计中的一个概念,是随机变量的一种数字特征.设 x 为随机变量,C为常数,则量E[(x−c)^k]称为X关于C点的k阶矩.比较重要的两种情况如下: 1.c=0,这时a_k=E(X^k ...