Codeforces 191C Fools and Roads(树链剖分)

题目链接:Codeforces 191C Fools and Roads

题目大意:给定一个N节点的数,然后有M次操作,每次从u移动到v,问说每条边被移动过的次数。

解题思路:树链剖分维护边,用一个数组标记即可,不需要用线段树。

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
const int maxn = 1e5 + 5;

int N, Q, ne, first[maxn], f[maxn], jump[maxn * 2];
int id, idx[maxn], top[maxn], far[maxn], son[maxn], dep[maxn], cnt[maxn];

struct Edge {
    int u, v;
    void set (int u, int v) {
        this->u = u;
        this->v = v;
    }
}ed[maxn * 2];

void dfs (int u, int pre, int d) {
    far[u] = pre;
    dep[u] = d;
    cnt[u] = 1;
    son[u] = 0;

    for (int i = first[u]; i + 1; i = jump[i]) {
        int v = ed[i].v;
        if (v == pre)
            continue;
        dfs(v, u, d + 1);
        cnt[u] += cnt[v];
        if (cnt[son[u]] < cnt[v])
            son[u] = v;
    }
}

void dfs(int u, int rot) {
    top[u] = rot;
    idx[u] = ++id;
    if (son[u])
        dfs(son[u], rot);
    for (int i = first[u]; i + 1; i = jump[i]) {
        int v = ed[i].v;
        if (v == far[u] || v == son[u])
            continue;
        dfs(v, v);
    }
}

inline void add_Edge(int u, int v) {
    ed[ne].set(u, v);
    jump[ne] = first[u];
    first[u] = ne++;
}

void init () {
    int u, v;
    ne = id = 0;
    memset(first, -1, sizeof(first));
    scanf("%d", &N);
    for (int i = 1; i < N; i++) {
        scanf("%d%d", &u, &v);
        add_Edge(u, v);
        add_Edge(v, u);
    }
    dfs(1, 0, 0);
    dfs(1, 1);
    for (int i = 0; i < N - 1; i++) {
        int t = i * 2;
        if (dep[ed[t].u] < dep[ed[t].v])
            swap(ed[t].u, ed[t].v);
    }
}

inline void add (int l, int r) {
    f[l]++, f[r + 1]--;
}

void solve (int u, int v) {
    int p = top[u], q = top[v];
    while (p != q) {
        if (dep[p] < dep[q]) {
            swap(p, q);
            swap(u, v);
        }
        add(idx[p], idx[u]);

        u = far[p];
        p = top[u];
    }

    if (u == v)
        return;

    if (dep[u] > dep[v])
        swap(u, v);
    add(idx[son[u]], idx[v]);
}

int main () {
    init();

    scanf("%d", &Q);
    int u, v;
    while (Q--) {
        scanf("%d%d", &u, &v);
        solve(u, v);
    }

    int mv = 0;
    for (int i = 1; i <= N; i++) {
        mv += f[i];
        f[i] = mv;
    }

    printf("%d", f[idx[ed[0].u]]);
    for (int i = 1; i < N - 1; i++)
        printf(" %d", f[idx[ed[i*2].u]]);
    printf("\n");
    return 0;
}
时间: 2024-09-30 20:55:06

Codeforces 191C Fools and Roads(树链剖分)的相关文章

Codeforces 191 C Fools and Roads (树链剖分)

题目链接~~> 做题感悟:这题在做了HDU 5044后就感觉很简单了. 解题思路: 先树链剖分一下,把树剖分成链,因为最后全是询问,so~可以线性操作.经过树链剖分后,就会形成许多链,但是每条边都有编号,相当于一个数组进行线性操作,这样,如果在 u  ~ v 去都增加 1 ,那么可以让 sum [ u ] += 1 ; sum [ v + 1 ] -= 1 ; 这里假设 v 的编号大.最后的时候只要从后往前遍历一次就可以了,得到所有的结果.明白这点后再加上树链剖分的思想就可以解决了. 代码: #

Codeforces 191 C Fools and Roads (树链拆分)

主题链接~~> 做题情绪:做了HDU 5044后就感觉非常easy了. 解题思路: 先树链剖分一下,把树剖分成链,由于最后全是询问,so~能够线性操作.经过树链剖分后,就会形成很多链,可是每条边都有编号,相当于一个数组进行线性操作,这样.如果在 u  ~ v 去都添加 1 .那么能够让 sum [ u ] += 1 ; sum [ v + 1 ] -= 1 ; 这里如果 v 的编号大. 最后的时候仅仅要从后往前遍历一次就能够了.得到全部的结果.明确这点后再加上树链剖分的思想就能够攻克了. 代码:

CodeForces 191C Fools and Roads 树上的前缀和 LCA

题目链接:点击打开链接 题意: 给定n个点的树. 下面m个操作,每次给一条路径上的边都染一次. 最后问:每个边被染色的次数. 和去年网赛的一道差不多,就是类似前缀和的做法, 我们在某个点+1然后从叶子节点到根节点求一个前缀和,这样某个点加1就相当于某个点到根的路径都加了1. 所以当我们给[u,v]染色时就 sum[u]++; sum[v]++; sum[LCA(u,v)]-=2; 再把重复的部分减掉即可. 最后求个前缀和. #include <cstdio> #include <vect

CF 191C Fools and Roads lca 或者 树链剖分

They say that Berland has exactly two problems, fools and roads. Besides, Berland has n cities, populated by the fools and connected by the roads. All Berland roads are bidirectional. As there are many fools in Berland, between each pair of cities th

CodeForces - 343D 树链剖分

题目链接:http://codeforces.com/problemset/problem/343/D 题意:给定一棵n个n-1条边的树,起初所有节点权值为0,然后m个操作. 1 x:把x为根的子树的点的权值修改为1: 2 x:把x结点到根路径上的点修改为0: 3 x:查询结点x的值. 思路:树链剖分. 对于操作1,子树操作记录下当前点为根时,dfs的最后一个点的id是多少(endid[]),然后就可以把子树操作用区间来维护了. 对于操作2,树链剖分. 对于3操作,线段树单点查询. #defin

Codeforces Round #425 (Div. 2) Problem D Misha, Grisha and Underground (Codeforces 832D) - 树链剖分 - 树状数组

Misha and Grisha are funny boys, so they like to use new underground. The underground has n stations connected with n - 1 routes so that each route connects two stations, and it is possible to reach every station from any other. The boys decided to h

D. Happy Tree Party CodeForces 593D【树链剖分,树边权转点权】

Codeforces Round #329 (Div. 2) D. Happy Tree Party time limit per test 3 seconds memory limit per test 256 megabytes input standard input output standard output Bogdan has a birthday today and mom gave him a tree consisting of n vertecies. For every

Codeforces Round #425 (Div. 2) D 树链剖分 + 树状数组维护区间

一看就知道 可以LCA判断做 也可以树链剖分拿头暴力 然而快速读入和线段树维护区间会T70 于是只能LCA? 线段树的常数不小 于是需要另外一种办法来进行区间加减和查询区间和 就是使用树状数组 这个题的代码 #include<iostream> #include<cstdio> #include<cmath> #include<algorithm> #include<vector> #include<cstring> using na

CodeForces 343D water tree(树链剖分)

Mad scientist Mike has constructed a rooted tree, which consists of n vertices. Each vertex is a reservoir which can be either empty or filled with water. The vertices of the tree are numbered from 1 to n with the root at vertex 1. For each vertex, t