3653: 谈笑风生

3653: 谈笑风生

链接

分析:

  $ans = min(deep[x] - 1, k) * siz[x] - 1 +\sum\limits_{y是u子树内的点}(siz[y] - 1)$

  前面的可以$O(1)$算,后面的那一部分可以dfs序+主席树维护。

  或者dfs的过程中+线段树合并。或者长链剖分。

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<cctype>
#include<set>
#include<queue>
#include<vector>
#include<map>
using namespace std;
typedef long long LL;

inline int read() {
    int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch==‘-‘)f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-‘0‘;return x*f;
}

const int N = 600005;
struct Edge{ int to, nxt; } e[N << 1];
int head[N], deep[N], fa[N], siz[N], st[N], ed[N], tr[N], En, Index, TimeIndex;
int ls[N * 20], rs[N * 20], Root[N];
LL sum[N * 20];

inline void add_edge(int u,int v) {
    ++En; e[En].to = v, e[En].nxt = head[u]; head[u] = En;
    ++En; e[En].to = u, e[En].nxt = head[v]; head[v] = En;
}
void dfs(int u) {
    deep[u] = deep[fa[u]] + 1;
    siz[u] = 1;
    st[u] = ++TimeIndex;tr[TimeIndex] = u;
    for (int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].to;
        if (v == fa[u]) continue;
        fa[v] = u;
        dfs(v);
        siz[u] += siz[v];
    }
    ed[u] = TimeIndex;
}
void update(int l,int r,int last,int &now,int p) {
    if (!now) now = ++Index;
    sum[now] += sum[last] + siz[tr[p]] - 1; /// !!!
    if (l == r) return ;
    int mid = (l + r) >> 1;
    if (deep[tr[p]] <= mid) {
        rs[now] = rs[last];
        update(l, mid, ls[last], ls[now], p);
    } else {
        ls[now] = ls[last];
        update(mid + 1, r, rs[last], rs[now], p);
    }
}
LL query(int l,int r,int last,int now,int L,int R) {
    if (L <= l && r <= R) return sum[now] - sum[last];
    int mid = (l + r) >> 1; LL res = 0;
    if (L <= mid) res = query(l, mid, ls[last], ls[now], L, R);
    if (R > mid) res += query(mid + 1, r, rs[last], rs[now], L, R);
    return res;
}
int main() {
    int n = read(), Q = read(), D;
    for (int i = 1; i < n; ++i) {
        int u = read(), v = read();
        add_edge(u, v);
    }
    dfs(1);
    for (int i = 1; i <= n; ++i) D = max(D, deep[i]);
    for (int i = 1; i <= n; ++i) {
        update(1, D, Root[i - 1], Root[i], i);
    }
    LL ans = 0;
    while (Q--) {
        int x = read(), k = read();
        ans = 1ll * min(deep[x] - 1, k) * (siz[x] - 1);
        if (deep[x] < D) ans += query(1, D, Root[st[x]], Root[ed[x]], deep[x] + 1, min(D, deep[x] + k));
        printf("%lld\n", ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/mjtcn/p/10288346.html

时间: 2025-01-01 23:12:14

3653: 谈笑风生的相关文章

bzoj 3653 谈笑风生——主席树

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3653 原来一直想怎么线段树合并.可是不会把角标挪一位. 查询的其实是子树内一段深度的点的 siz 和.因为是子树内,所以按 dfs 序建立主席树,角标是 dep ,值是 siz . 注意 long long .而且数组 *19 就会 RE ,*20就好了.不知为何. #include<iostream> #include<cstdio> #include<cstring

BZOJ 3653 谈笑风生

ORZ blutrex...... 主席树. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxv 1000500 #define maxq 1000500 #define maxe 1600500 using namespace std; struct edge { long long v,nxt; }e[maxe]; struct an

【BZOJ】【3653】谈笑风生

dfs序+可持久化线段树 好吧……是我too naive 这题……$$ans=min(dep[x],k)×(size[x]-1)+\sum_{y在x的子树中,且dis(x,y)<=k}(size[y]-1)$$ 那么重点是后面sigma的部分,这里看到子树中信息的统计可以用dfs序……但是对子树中dep在某个范围内的点的size求和? 我们可以用权值线段树呀-dep做关键字,size的和是线段树上统计的额外信息,那么对整个dfs序做可持久化线段树就可以了……查询的时候就像普通线段树一样. 调了很

【BZOJ-3653】谈笑风生 DFS序 + 可持久化线段树

3653: 谈笑风生 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 628  Solved: 245[Submit][Status][Discuss] Description 设T 为一棵有根树,我们做如下的定义:• 设a和b为T 中的两个不同节点.如果a是b的祖先,那么称“a比b不知道高明到哪里去了”.• 设a 和 b 为 T 中的两个不同节点.如果 a 与 b 在树上的距离不超过某个给定常数x,那么称“a 与b 谈笑风生”.给定一棵n个节点的

【20151105noip膜你赛】bzoj3652 bzoj3653

题目仿佛在讽刺我... 第一题: 题解: 考虑枚举区间右端点,维护所以左到当前的 and 和 or .注意 and 每次变化至少有一个二进制位从1变 0,or 每次至少有一个位从0变 1,所以最多有log段不同的值.用两个链表维护这log个值,暴力计算答案即可.O( nlogn) 我原本打的是一个树状数组的O(nlognlogn)算法..然后被卡了..只有50分.. 看了看奥爷爷的代码,发现他直接用一个链表同时维护and和or值,真奇怪啊不是(logn)^2吗..然后男神说这个也是log级别的,

[BZOJ3653]谈笑风生

试题描述 设T 为一棵有根树,我们做如下的定义:? 设a和b为T 中的两个不同节点.如果a是b的祖先,那么称"a比b不知道高明到哪里去了".? 设a 和 b 为 T 中的两个不同节点.如果 a 与 b 在树上的距离不超过某个给定常数x,那么称"a 与b 谈笑风生".给定一棵n个节点的有根树T,节点的编号为1 到 n,根节点为1号节点.你需要回答q 个询问,询问给定两个整数p和k,问有多少个有序三元组(a;b;c)满足:1. a.b和 c为 T 中三个不同的点,且 a

POJ 3653 &amp; ZOJ 2935 &amp; HDU 2722 Here We Go(relians) Again(最短路dijstra)

题目链接: PKU:http://poj.org/problem?id=3653 ZJU:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1934 HDU:http://acm.hdu.edu.cn/showproblem.php?pid=2722 Description The Gorelians are a warlike race that travel the universe conquering new world

老码农教你在 StackOverflow 上谈笑风生

作为一个高大上的码农,你肯定用到过 StackOverflow,必须的.会有人否定这个断言么?那他恐怕不是真正的码农,或者说还没入门.StackOverflow 对于码农的重要性,基本就和诸葛亮对刘备的重要性差不多,它上知 Java 下知 MySQL,中间懂得各种算法.只要你拥有与它沟通的技巧,它几乎可以回答你遇到的任何技术问题. 不过,很多码农对它的体验也就仅限于此了.查询一下,找到问题,然后把里边的代码复制粘贴到自己的 IDE 里,然后接着调试代码.万一没有找到符合的条目,就只好去其他地方问

【NOI模拟】谈笑风生(主席树)

题目描述 设 T 为一棵有根树,我们做如下的定义: 设 a 和 b 为 T 中的两个不同节点.如果 a 是 b 的祖先,那么称 “ a 比 b 不知道高明到哪里去了 ” . 设 a 和 b 为 T 中的两个不同节点.如果 a 与 b 在树上的距离不超过某个给定常数 x ,那么称 “ a 与 b 谈笑风生 ” . 给定一棵 n 个节点的有根树 T ,节点的编号为 1-n ,根节点为 1 号节点.你需要回答 q 个询问,询问给定两个整数 p 和 k ,问有多少个有序三元组 (a,b,c) 满足:1.