桥【2021牛客寒假算法基础集训营5 J】【点分治】

美丽的路径

https://ac.nowcoder.com/acm/contest/9985/A

题目链接
显然,一棵树有条割边(也指桥),于是如果要使最后只有条桥,那么当时候,实际上我们要将长度为的链给“取消割边”,而取消割边的方法就是通过连边。一条长度为的边,会产生的贡献
所以,我们假设现在找到的一个点举例目前的根节点距离为,要找一个根节点的另一个方向的距离为,那么此时产生的贡献是。所以,我们维护一个“个数”,一个“”就可以求解了。
然后,点分治的基本操作了。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
#include <unordered_map>
#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define pii pair<int, int>
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 1e5 + 7;
int N, L, R, head[maxN], cnt;
struct Eddge
{
    int nex, to;
    Eddge(int a=-1, int b=0):nex(a), to(b) {}
} edge[maxN << 1];
void addEddge(int u, int v)
{
    edge[cnt] = Eddge(head[u], v);
    head[u] = cnt ++;
}
inline void _add(int u, int v) { addEddge(u, v); addEddge(v, u); }
void init()
{
    cnt = 0;
    for(int i = 1; i <= N; i ++) head[i] = -1;
}
int ql, qr;
int root, siz[maxN], all, son[maxN], maxx;
bool vis[maxN] = {false};
void fid_root(int u, int fa)
{
    siz[u] = 1; son[u] = 0;
    for(int i = head[u], v; ~i; i = edge[i].nex)
    {
        v = edge[i].to;
        if(vis[v] || v == fa) continue;
        fid_root(v, u);
        siz[u] += siz[v];
        son[u] = max(son[u], siz[v]);
    }
    son[u] = max(son[u], all - siz[u]);
    if(son[u] < maxx)
    {
        maxx = son[u];
        root = u;
    }
}
struct Bit_Tree
{
    ll t[maxN] = {0};
    void add(int i, ll v) { while(i <= N) { t[i] += v; i += lowbit(i); } }
    ll query(int i) { ll ans = 0; while(i) { ans += t[i]; i -= lowbit(i); } return ans; }
} num, sum;
int dis[maxN];
int que[maxN], top, tail;
void dfs(int u, int fa)
{
    que[tail ++] = u;
    for(int i = head[u], v; ~i; i = edge[i].nex)
    {
        v = edge[i].to;
        if(vis[v] || v == fa) continue;
        dis[v] = dis[u] + 1;
        dfs(v, u);
    }
}
ll ans = 0;
void Divide(int u)
{
    vis[u] = true;
    top = tail = 0;
    ll tmp_num, tmp_sum;
    num.add(1, 1);
//    sum.add(1, 0);
    dis[u] = 0;
    for(int i = head[u], v; ~i; i = edge[i].nex)
    {
        v = edge[i].to;
        if(vis[v]) continue;
        dis[v] = dis[u] + 1;
        dfs(v, u);
        for(int j = top, id, x; j < tail; j ++)
        {
            id = que[j];
            x = dis[id];
            if(qr - x < 0) continue;
            tmp_num = num.query(qr - x + 1) - num.query(max(0, ql - x));
            tmp_sum = sum.query(qr - x + 1) - sum.query(max(0, ql - x));
            ans += 6LL * (tmp_num * x + tmp_sum);
        }
        while(top < tail)
        {
            int id = que[top ++];
            int x = dis[id];
            if(x > qr) continue;
            num.add(x + 1, 1);
            sum.add(x + 1, x);
        }
    }
    if(ql == 0) ans ++; //example:(u, u, u)
    for(int i = 0, id, x; i < tail; i ++)
    {
        id = que[i];
        x = dis[id];
        if(x > qr) continue;
        num.add(x + 1, -1);
        sum.add(x + 1, -x);
    }
    num.add(1, -1);
//    sum.add(1, 0);
    int tot_siz = all;
    for(int i = head[u], v; ~i; i = edge[i].nex)
    {
        v = edge[i].to;
        if(vis[v]) continue;
        all = siz[u] > siz[v] ? siz[v] : tot_siz - siz[u];
        maxx = N;
        fid_root(v, u);
        Divide(root);
    }
}
int main()
{
    scanf("%d%d%d", &N, &L, &R);
    init();
    for(int i = 1, u, v; i < N; i ++)
    {
        scanf("%d%d", &u, &v);
        _add(u, v);
    }
    if(L >= N)
    {
        printf("0\n");
        return 0;
    }
    R = min(R, N - 1);
    ql = N - 1 - R; qr = N - 1 - L;
    all = N; maxx = N;
    fid_root(1, 0);
    Divide(root);
    printf("%lld\n", ans);
    return 0;
}
/*
4 1 1
1 2
2 3
3 4
ans:24
4 1 2
1 2
2 3
3 4
ans:42
*/
全部评论

相关推荐

10-06 12:46
门头沟学院 Java
跨考小白:定时任务启动
点赞 评论 收藏
分享
1 收藏 评论
分享
牛客网
牛客企业服务