zoukankan      html  css  js  c++  java
  • [Luogu] U18430 萌萌的大河

    https://www.luogu.org/problemnew/show/U18430

    思路比较好想

    树链剖分

    对于1操作

      只需将以该点为根的子树打标记,将所有数存入数组排序

      每次进行1操作时,判断若该点已经被标记过,则操作无效

    对于操作2

      在原树中求出lca,若lca被标记过,lca就是询问的两个点中

      编号较小的那个,lca值不改变

    对于操作3

      若该点打过标记,输出该点与根的这条链上被打过标记的

      深度最小节点编号a与该节点编号的差+a的深度

    #include <iostream>
    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    
    using namespace std;
    const int N = 1e6 + 10;
    
    #define yxy getchar()
    #define lson jd << 1
    #define rson jd << 1 | 1
    
    int n, Q, now = 1, tim, w1, w2, w3;
    int head[N], Num[N], deep[N], fa[N], lnum[N], rnum[N], son[N], topp[N], siz[N], tree[N], g_min[N << 2];
    struct Node{int u, v, nxt;} G[N << 1];
    
    inline int read(){
        int x = 0; char c = yxy;
        while(c < '0' || c > '9') c = yxy;
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = yxy;
        return x;
    }
    
    inline void add(int u, int v){
        G[now].u = u; G[now].v = v; G[now].nxt = head[u]; head[u] = now ++;
    }
    
    void dfs_1(int u, int father, int dep){
        fa[u] = father;
        deep[u] = dep;
        siz[u] = 1;
        for(int i = head[u]; ~ i; i = G[i].nxt){
            int v = G[i].v;
            if(v != father){
                dfs_1(v, u, dep + 1);
                siz[u] += siz[v];
                if(siz[v] > siz[son[u]]) son[u] = v;
            }
        }
    }
    
    void dfs_2(int u, int tp){
        topp[u] = tp;
        lnum[u] = ++ tim;
        tree[u] = tim;
        Num[tim] = u;
        if(!son[u]) {rnum[u] = tim; return ;}
        dfs_2(son[u], tp);
        for(int i = head[u]; ~ i; i = G[i].nxt){
            int v = G[i].v;
            if(v != fa[u] && v != son[u]) dfs_2(v, v);
        }
        rnum[u] = tim;
    }
    
    void Poi_A(int l, int r, int jd, int x){
        if(l == r) {
            if(g_min[jd]) w1 = 1;
            return ;
        }
        if(g_min[jd]) {
            g_min[lson] = g_min[jd];
            g_min[rson] = g_min[jd];
        }
        int mid = (l + r) >> 1;
        if(x <= mid) Poi_A(l, mid, lson, x);
        else Poi_A(mid + 1, r, rson, x);
    }
    
    void Sec_G(int l, int r, int jd, int x, int y, int yg){
        if(x <= l && r <= y){
            g_min[jd] = yg;
            return ;
        }
        int mid = (l + r) >> 1;
        if(x <= mid) Sec_G(l, mid, lson, x, y, yg);
        if(y > mid)  Sec_G(mid + 1, r, rson, x, y, yg);
    }
    
    int calc_lca(int x, int y){
        int tp1 = topp[x], tp2 = topp[y];
        while(tp1 != tp2){
            if(deep[tp1] < deep[tp2]) swap(tp1, tp2), swap(x, y);
            x = fa[tp1];
            tp1 = topp[x];
        }
        return deep[x] > deep[y] ? y : x;
    }
    
    void Sec_A(int l, int r, int jd, int x, int y){
        if(x <= l && r <= y){
            w2 = g_min[jd];
            return ;
        }
        if(g_min[jd]) {
            g_min[lson] = g_min[jd];
            g_min[rson] = g_min[jd];
        }
        int mid = (l + r) >> 1;
        if(x <= mid) Sec_A(l, mid, lson, x, y);
        if(y > mid)  Sec_A(mid + 1, r, rson, x, y);
    }
    
    int get_answer(int l, int r, int x){
        int L = l, R = r, ret;
        while(L <= R){
            int mid = (L + R) >> 1;
            if(Num[mid] <= x) L = mid + 1, ret = mid;
            else R = mid - 1;
        }
        return ret - l;
    }
    
    int main()
    {
        n = read(); Q = read();
        for(int i = 1; i <= n; i ++) head[i] = -1;
        for(int i = 1; i < n; i ++) {
            int u = read(), v = read();
            add(u, v); add(v, u);
        }
        dfs_1(1, 0, 1);
        dfs_2(1, 1);
        while(Q --){
            int opt = read();
            if(opt == 1){
                int x = read();
                if(!son[x]) continue ;
                w1 = 0;
                Poi_A(1, n, 1, tree[x]);
                if(w1) continue ;
                Sec_G(1, n, 1, lnum[x], rnum[x], x);
                sort(Num + lnum[x] + 1, Num + rnum[x] + 1); 
            }
            else if(opt == 2){
                int x = read(), y = read();
                int Lca_now = calc_lca(x, y);
                w1 = 0;
                Poi_A(1, n, 1, tree[Lca_now]);
                if(w1) printf("%d
    ", min(x, y));
                else printf("%d
    ", Lca_now);
            }
            else {
                int x = read();
                w1 = 0;
                Poi_A(1, n, 1, tree[x]);
                if(!w1) printf("%d
    ", deep[x]);
                else {
                    Sec_A(1, n, 1, lnum[x], rnum[x]);
                    printf("%d
    ", get_answer(lnum[w2], rnum[w2], x) + deep[w2]);
                }
            }
        }
        return 0;
    }
  • 相关阅读:
    bug的生命周期
    性能测试的流程
    通过画因果图来写测试用例的步骤为___、___、___、___及把因果图转换为状态图共五个步骤。&#160;利用因果图生成测试用例的基本步骤是:
    集成测试中自顶向下集成和自底向上集成两个策略的理解,要谈出它们各自的优缺点和主要适应于哪种类型测试;
    Spring中的八大设计模式
    ssh
    window实用快捷键-win篇
    解决Chrome浏览器“崩溃啦”的问题!
    C语言-格式输出
    AIDA64+RemotePanel 组副屏电脑状态监视器 旧手机废物利用 wifi/数据线 adb驱动
  • 原文地址:https://www.cnblogs.com/shandongs1/p/8321721.html
Copyright © 2011-2022 走看看