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下取整. 问你最大能获得的收益为多少? 思路: ...
随机推荐
- Apache Solr JMX服务 RCE 漏洞复现
Apache Solr JMX服务 RCE 漏洞复现 ps:Apache Solr8.2.0下载有点慢,需要的话评论加好友我私发你 0X00漏洞简介 该漏洞源于默认配置文件solr.in.sh中的EN ...
- 11种常用css样式学习大结局滚动条与显示隐藏
滚动条展示 overflow-x: hidden;/*是否对内容的左/右边缘进行裁剪*/overflow-y: hidden;/*是否对内容的上/下边缘进行裁剪*/overflow:scroll;/* ...
- 【POJ - 3186】Treats for the Cows (区间dp)
Treats for the Cows 先搬中文 Descriptions: 给你n个数字v(1),v(2),...,v(n-1),v(n),每次你可以取出最左端的数字或者取出最右端的数字,一共取n次 ...
- ubuntu18.04误删apt-get命令恢复总结
1.背景 由于使用aptitude命令替换了apt-get命令后感到后悔,想要恢复apt-get命令,特此总结以下踩过的坑 aptitude和apt-get的区别:https://www.cnblog ...
- PHP0016:PHP http协议
post提交请求头
- FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecate;的解决办法
踩坑场景 报错FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecate; 解决办法 1.升级numpy ...
- CF594D REQ [离线+树状数组,欧拉函数]
设 \[x = \prod_{i=1}^{cnt} p_i^{k_i} [p_i\in prime]\] 那么显然 \[\varphi(x) = x*\frac{1} {\prod_{i=1}^{cn ...
- vim 配置 jedi-vim( ubuntu:15.10 )
确保 vim 支持 python3 或者 python 如果你已经安装了 vim, 可以通过vim --version, 在输出中找到 +python3 或者 +python 字样的话, 就可以跳过该 ...
- Swagger2 @ApiIgnore注解忽略接口在swagger-ui.html中显示
果项目中定义了一个controller,但是我们又不想把这个接口在swagger-ui.html中体现出来怎么办?不要着急,Swagger2已经替我们想到了这个问题,只要把@ApiIgnore放到你想 ...
- Miller-Rabin素数检测算法 acm模板
Miller-Rabin素数检测算法 其基于以下两个定理. Fermat小定理 若n是素数,则∀a(a̸≡0(modn))\forall a(a \not\equiv 0 \pmod{n})∀a(a̸ ...