Codeforces Round #381 (Div. 2)D. Alyona and a tree

本文解析了一种针对有根树的控制点计数问题,提供了两种解决方案:一是使用线段树实现NlogN复杂度的区间更新算法;二是通过巧妙的树上区间更新策略达到线性时间复杂度。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意,有一个有根树,每个加点都有一个val,每条边都有一个权值,如果u是v的子树,并且dis(u,v)<=val(u),那么认为v可以控制u,问每个点可以控制多少个点。

有两种做法一种nlogn线段树区间更新。还有一种树上区间更新的神奇算法。

1:nlogn:

线段树维护的是当前栈里元素的可以控制节点的个数。

建立两个栈,一个放栈里元素的下标,一个放栈里元素到他所有父亲的距离,每遍历到一个点,先二分查找它可以到达的最远父亲。然后更新这个父亲在栈里的下标到栈顶-1,全部加1,然后每个节点的答案就是它出栈的时候它在线段树里面的值。

2:n

对于线性的数据,l到r区间更新可以看做在l-1处减1,r+1处加1,那么在所有的更新操作进行完之后,sum[i] += sum[i-1];

这题是一个树,如果在树上需要对l到r这一段全部加上一个数,那么让l的父亲的减去这个数,r加上这个数,由深度排列,sum[i] += sum[(i的所有儿子)];

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 2e5+100;

struct edge{
    int to,w;
};

vector<edge> G[N];
int val[N];
ll que[N];
ll dis[N];
int sum[N<<2];
int ans[N];
int n;
void pushdown(int rt){
    if(sum[rt]){
        sum[rt<<1]+= sum[rt];
        sum[rt<<1|1] += sum[rt];
        sum[rt] = 0;
    }

}

void update(int L,int R,int l,int r,int rt,int c){
    if(l>= L && r <= R){
        sum[rt] += c;
        return;
    }
    pushdown(rt);
    int mid = (r+l)>>1;
    if(mid >= L) update(L,R,l,mid,rt<<1,c);
    if(mid < R) update(L,R,mid+1,r,rt<<1|1,c);
}
int query(int x,int l,int r,int rt){
    if(l == r){
        return sum[rt];
    }
    pushdown(rt);
    int mid = (r+l)>>1;
    if(mid>= x)return query(x,l,mid,rt<<1);
    else return query(x,mid+1,r,rt<<1|1);
}
void update2(int x,int l,int r,int rt){
    if(l == r){
        sum[rt]=  0;
        return ;
    }
    pushdown(rt);
    int mid = (r+l)>>1;
    if(mid >= x) update2(x,l,mid,rt<<1);
    else update2(x,mid+1,r,rt<<1|1);
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值