zoukankan      html  css  js  c++  java
  • BZOJ 3307: 雨天的尾巴( LCA + 线段树合并 )

    路径(x, y) +z : u处+z, v处+z, lca(u,v)处-z, fa(lca)处-z, 然后dfs一遍, 用线段树合并. O(M log M + M log N). 复杂度看起来不高, 但是跑起来很慢.

    另一种做法是先树链剖分, 转成序列上的情况, 然后依旧是差分+线段树维护, O(M log N log M). 但是实际跑起来好像更快... 

    ------------------------------------------------------------------------------

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    #include<algorithm>
     
    using namespace std;
     
    const int maxn = 100009;
     
    int N, M;
    int Hash[maxn], Hn;
     
    template<class T>
    inline void Min(T &x, T t) {
    if(t < x) x = t;
    }
    template<class T>
    inline void Max(T &x, T t) {
    if(t > x) x = t;
    }
     
    inline int getint() {
    char c = getchar();
    for(; !isdigit(c); c = getchar());
    int ret = 0;
    for(; isdigit(c); c = getchar())
    ret = ret * 10 + c - '0';
    return ret;
    }
     

    struct L {

    int x;
    L* n;
    } Lpool[maxn * 4], *Pt = Lpool, *Head[maxn];
     
    inline void AddL(int a, int b) {
    Pt->x = b, Pt->n = Head[a], Head[a] = Pt++;
    }
     
    struct O {
    int x, y, z;
    } o[maxn];
     
    struct edge {
    int t;
    edge* n;
    } E[maxn << 1], *ept = E, *H[maxn];
     
    inline void AddEdge(int u, int v) {
    ept->t = v, ept->n = H[u], H[u] = ept++;
    }
     
    void Init() {
    Hn = 0;
    int u, v;
    N = getint(), M = getint();
    for(int i = 1; i < N; i++) {
    u = getint() - 1, v = getint() - 1;
    AddEdge(u, v);
    AddEdge(v, u);
    }
    for(int i = 0; i < M; i++) {
    o[i].x = getint() - 1;
    o[i].y = getint() - 1;
    Hash[Hn++] = o[i].z = getint();
    }
    Hash[Hn++] = 0;
    sort(Hash, Hash + Hn);
    Hn = unique(Hash, Hash + Hn) - Hash;
    for(int i = 0; i < M; i++)
    o[i].z = lower_bound(Hash, Hash + Hn, o[i].z) - Hash;
    }
     
    int top[maxn], sz[maxn], ch[maxn], fa[maxn], dep[maxn];
    int Top;
     
    void dfs(int x) {
    sz[x] = 1, ch[x] = -1;
    for(edge* e = H[x]; e; e = e->n) if(e->t != fa[x]) {
    dep[e->t] = dep[x] + 1;
    fa[e->t] = x;
    dfs(e->t);
    sz[x] += sz[e->t];
    if(!~ch[x] || sz[ch[x]] < sz[e->t]) ch[x] = e->t;
    }
    }
     
    void DFS(int x) {
    top[x] = Top;
    if(~ch[x]) DFS(ch[x]);
    for(edge* e = H[x]; e; e = e->n)
    if(e->t != fa[x] && e->t != ch[x]) DFS(Top = e->t);
    }
     
    int LCA(int x, int y) {
    for(; top[x] != top[y]; x = fa[top[x]])
    if(dep[top[x]] < dep[top[y]]) swap(x, y);
    return dep[x] < dep[y] ? x : y;
    }
     
    struct Node {
    Node *lc, *rc;
    int mx, Id;
    inline void upd() {
    mx = -maxn, Id = maxn;
    if(lc) Max(mx, lc->mx);
    if(rc) Max(mx, rc->mx);
    if(lc && lc->mx == mx) Min(Id, lc->Id);
    if(rc && rc->mx == mx) Min(Id, rc->Id);
    }
    } pool[maxn * 70], *pt = pool, *V[maxn];
     
    int Val, Pos;
     
    void Modify(Node*&t, int l, int r) {
    if(!t)
    (t = pt++)->mx = 0;
    int m = (l + r) >> 1;
    if(l == r) {
    t->mx += Val;
    t->Id = m;
    } else {
    Pos <= m ? Modify(t->lc, l, m) : Modify(t->rc, m + 1, r);
    t->upd();
    }
    if(!t->mx) t = 0;
    }
     
    Node* Merge(Node* a, Node* b, int l, int r) {
    int m = (l + r) >> 1;
    if(!a) return b;
    if(!b) return a;
    if(l != r) {
    a->lc = Merge(a->lc, b->lc, l, m);
    a->rc = Merge(a->rc, b->rc, m + 1, r);
    a->upd();
    } else
    a->mx += b->mx;
    return a;
    }
     
    int ans[maxn];
     
    void calc(int x) {
    for(L* t = Head[x]; t; t = t->n) {
    if(t->x > 0)
    Pos = t->x, Val = 1;
    else
    Pos = -t->x, Val = -1;
    Modify(V[x], 1, Hn);
    }
    for(edge* e = H[x]; e; e = e->n) if(e->t != fa[x]) {
    calc(e->t);
    V[x] = Merge(V[x], V[e->t], 1, Hn);
    }
    ans[x] = V[x] ? V[x]->Id : 0;
    }
     
    void Work() {
    fa[0] = -1;
    dep[0] = 0;
    dfs(0);
    DFS(Top = 0);
    for(int i = 0; i < M; i++) {
    int lca = LCA(o[i].x, o[i].y);
    AddL(o[i].x, o[i].z);
    AddL(o[i].y, o[i].z);
    AddL(lca, -o[i].z);
    if(~fa[lca]) AddL(fa[lca], -o[i].z);
    }
    calc(0);
    for(int i = 0; i < N; i++)
    printf("%d ", Hash[ans[i]]);
    }
     

    int main() {

    Init();
    Work();
    return 0;
    }

    ------------------------------------------------------------------------------ 

    3307: 雨天的尾巴

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 267  Solved: 127
    [Submit][Status][Discuss]

    Description

    N个点,形成一个树状结构。有M次发放,每次选择两个点x,y
    对于x到y的路径上(含x,y)每个点发一袋Z类型的物品。完成
    所有发放后,每个点存放最多的是哪种物品。

    Input

    第一行数字N,M
    接下来N-1行,每行两个数字a,b,表示a与b间有一条边
    再接下来M行,每行三个数字x,y,z.如题

    Output


    输出有N行
    每i行的数字表示第i个点存放最多的物品是哪一种,如果有
    多种物品的数量一样,输出编号最小的。如果某个点没有物品
    则输出0

    Sample Input

    20 50
    8 6
    10 6
    18 6
    20 10
    7 20
    2 18
    19 8
    1 6
    14 20
    16 10
    13 19
    3 14
    17 18
    11 19
    4 11
    15 14
    5 18
    9 10
    12 15
    11 14 87
    12 1 87
    14 3 84
    17 2 36
    6 5 93
    17 6 87
    10 14 93
    5 16 78
    6 15 93
    15 5 16
    11 8 50
    17 19 50
    5 4 87
    15 20 78
    1 17 50
    20 13 87
    7 15 22
    16 11 94
    19 8 87
    18 3 93
    13 13 87
    2 1 87
    2 6 22
    5 20 84
    10 12 93
    18 12 87
    16 10 93
    8 17 93
    14 7 36
    7 4 22
    5 9 87
    13 10 16
    20 11 50
    9 16 84
    10 17 16
    19 6 87
    12 2 36
    20 9 94
    9 2 84
    14 1 94
    5 5 94
    8 17 16
    12 8 36
    20 17 78
    12 18 50
    16 8 94
    2 19 36
    10 18 36
    14 19 50
    4 12 50

    Sample Output

    87
    36
    84
    22
    87
    87
    22
    50
    84
    87
    50
    36
    87
    93
    36
    94
    16
    87
    50
    50



    1<=N,M<=100000
    1<=a,b,x,y<=N
    1<=z<=10^9

    HINT

    Source

  • 相关阅读:
    使用PHP类库PHPqrCode生成二维码
    40+个对初学者非常有用的PHP技巧
    (高级篇)jQuery学习之jQuery Ajax用法详解
    lerna管理前端模块实践
    Node.js:深入浅出 http 与 stream
    从koa-session源码解读session本质
    Elastichsearch实践
    Linux代理搭建TinyProxy
    linux常用命令
    node前后端同构的踩坑经历
  • 原文地址:https://www.cnblogs.com/JSZX11556/p/5194939.html
Copyright © 2011-2022 走看看