计蒜客2018蓝桥A组模拟赛(一)青出于蓝胜于蓝(dfs序+线段树)

原创 2018年04月16日 22:58:38

题目:

武当派一共有 n 人,门派内 n 人按照武功高低进行排名,武功最高的人排名第 1,次高的人排名第 2,… 武功最低的人排名第 n。现在我们用武功的排名来给每个人标号,除了祖师爷,每个人都有一个师父,每个人可能有多个徒弟。

我们知道,武当派人才辈出,连祖师爷的武功都只能排行到 p。也就是说徒弟的武功是可能超过师父的,所谓的青出于蓝胜于蓝。

请你帮忙计算每个人的所有子弟(包括徒弟的徒弟,徒弟的徒弟的徒弟….)中,有多少人的武功超过了他自己。

1 <= n <= 100000

分析:

这道题就是:给一棵带权树,求每个节点的子树上有多少个权值比它小的点。

显然,对每个节点遍历子树肯定会超时。

我们对这棵树dfs一次,按照dfs的顺序给每个点编号。这样,按照遍历的顺序我们就得到了一个线性序列。更重要的是,点 i 的子树在线性序列中就紧跟点 i 后面。所以我们如果知道它子树这一段的起点 l[i] 和终点 r[i],就可以用线段树解决。很显然,dfs的顺序得到的编号就是 l[i]。在dfs的时候,某个点的子树遍历完了的时候,再记录一下 r[i]

这样,在dfs得到的线性序列中,点 i 的子树就是 l[i]r[i]

我们从小排名到大排名更新和查询,对第 i 名的人,比他名次小的人数 l[i]r[i] 的人数和。因为我们是按照从小到达查询更新,所以比 i 排名大的点还没更新进树里。

代码:

#include <bits/stdc++.h>
using namespace std;
#define ms(a,b) memset(a,b,sizeof(a))
#define lson rt*2,l,(l+r)/2
#define rson rt*2+1,(l+r)/2+1,r
typedef unsigned long long ull;
typedef long long ll;
const int MAXN = 100005;
const double EPS = 1e-8;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
int tree[MAXN << 2], n, p, l[MAXN], r[MAXN], times;
vector<int>G[MAXN];

void init() {
    times = 0;
    ms(tree, 0);
}

void pushup(int rt) {
    tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
}

void dfs(int u, int fa) {
    l[u] = ++times;
    for (int i = 0; i < (int)G[u].size(); i++) {
        int v = G[u][i];
        if (v != fa) {
            dfs(v, u);
        }
    }
    r[u] = times;
}

int query(int L, int R, int rt, int l, int r) {
    if (L <= l && R >= r) {
        return tree[rt];
    }
    int ret = 0;
    if (L <= (l + r) / 2)   ret += query(L, R, lson);
    if (R > (l + r) / 2)    ret +=query(L,R,rson);
    return ret;
}

void update(int k, int rt, int l, int r) {
    if (l == r) {
        tree[rt] = 1;
        return;
    }
    if (k <= (l + r) / 2)   update(k, lson);
    else    update(k, rson);
    pushup(rt);
}

int main() {
    ios::sync_with_stdio(false);
    cin >> n >> p;
    init();
    for (int i = 0; i < n - 1; i++) {
        int u, v;
        cin >> u >> v;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs(p, -1);
    // for(int i=1;i<=n;i++){
    //  cout <<i << " " << l[i] << " " << r[i] << endl;
    // }
    for (int i = 1; i <= n; i++) {
        cout << query(l[i], r[i], 1, 1, n) << " \n"[i == n];
        update(l[i], 1, 1, n);
    }

    return 0;
}

iOS开发-全面解析iOS蓝牙BLE4.0开发

只要你会OC基础,会写HelloWorld,你就可以实现iOS的蓝牙通信功能,实现蓝牙小项目也不在话下,作者会带领大家详细分析BLE4.0原理,通过分析xcode使用的蓝牙API,让学者能够得心应手的实现蓝牙BLE4.0的开发
  • 2017年03月24日 13:36

计蒜客蓝桥杯模拟赛---青出于蓝而胜于蓝

题目链接这道题综合运用了搜索和树状数组原理如下先DFS一下,搜索一整棵树,将树的每一个节点标记上时序(即DFS搜索时候的顺序)记录两个,一个是往下搜的时序,一个是往回回溯的时序,这样这两个标记可以表示...
  • wjhshuai
  • wjhshuai
  • 2018-03-13 21:16:25
  • 251

2018蓝桥杯模拟赛--数列求值

题目链接:https://nanti.jisuanke.com/t/20688 样例输入1 1 50.50 25.50 10.15 样例输出1 ...
  • xiaolonggezte
  • xiaolonggezte
  • 2018-01-22 11:45:20
  • 214

计蒜客 2018 蓝桥杯省赛 B 组模拟赛(一)题解

传送门 A: 直接暴力跑答案 ans = 1;B: 还是暴力算模拟一遍即可 ans = 571;C: 这道题还是暴力算有多少个满足条件的即可, 就是模拟的时候有点恶心, 要考虑到边界情况即可....
  • Anxdada
  • Anxdada
  • 2018-03-22 20:45:02
  • 326

计蒜客2018蓝桥杯省赛B组模拟赛(一)题目及解析(未完待续)

一、题目列表 A. 结果填空:年龄        分值: 3 B. 结果填空:开关灯    分值: 7 C. 结果填空:U型数字 分值: 9 D. 代码填空:LIS        分值: 11 E....
  • cr496352127
  • cr496352127
  • 2018-01-21 11:39:53
  • 3180

计蒜客 2018蓝桥杯省赛 B组模拟赛(五) A题 矩阵求和(java)

【题目链接】:https://nanti.jisuanke.com/t/25084【题目描述】:给你一个 n×n 的矩阵,里面填充 1到 n x n。例如当 n 等于 3 的时候,填充的矩阵如下。1 ...
  • xiaodingqq
  • xiaodingqq
  • 2018-03-27 14:50:59
  • 173

2018 蓝桥杯省赛 B 组模拟赛(一) G. 数列求值(2个未知数 假设一个未知数为0)

对于一个含有 n+2个元素的数列A0, A1, ... , An,满足这样的递归公式: Ai = (Ai−1 + Ai+1) /2−Ci​   1≤i≤n        现在我们知道A0, ...
  • deepseazbw
  • deepseazbw
  • 2018-01-22 20:14:16
  • 258

2018 蓝桥杯省赛 B 组模拟赛(一)G. 数列求值

对于一个含有 n+2个元素的数列,满足这样的递归公式现在我们知道 和的值。现在请你帮忙计算的值。输入格式第一行输入一个整数 n(1≤n≤1000)。第二行输入两个数 和 ,接着是 n个数据分别是。所有...
  • CS33sun
  • CS33sun
  • 2018-03-09 22:54:48
  • 130

2018 蓝桥杯省赛 A 组模拟赛 蒜头君下棋

题目链接:点击打开链接 题意:一个n*M的棋盘上让你放马,马和马之间不能攻击。问能放多少匹马。 题解:最开始是以为是一道搜索题。然后一看数据范围。瞬间懵逼。发现这道题,是个规律题。而且规律错综复杂...
  • PK__PK
  • PK__PK
  • 2018-03-27 09:49:14
  • 122

计蒜客蓝桥杯模拟赛题目

  • 2017年04月04日 22:47
  • 118KB
  • 下载
收藏助手
不良信息举报
您举报文章:计蒜客2018蓝桥A组模拟赛(一)青出于蓝胜于蓝(dfs序+线段树)
举报原因:
原因补充:

(最多只允许输入30个字)