zoukankan      html  css  js  c++  java
  • 洛谷P3248 [HNOI2016]树(主席树 倍增 )

    题意

    题目链接

    Sol

    从上午九点淦到现在qwq

    思路比较简单,就是把每次加入的一坨点看成一个,然后直接倍增搞。。

    然后慢慢调就可以了。。。

    最后数量级会到达(10^{10}),所以应该开long long

    #include<bits/stdc++.h>
    #define Pair pair<LL, LL>
    #define MP make_pair
    #define fi first
    #define se second
    #define LL long long 
    #define int long long  
    using namespace std;
    const int MAXN = 1e5 + 10, B = 17, SS = 7e6 + 10;
    inline LL read() {
        char c = getchar(); LL x = 0, f = 1;
        while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * f;
    }
    int N, M, Q;
    vector<int> v[MAXN];
    int siz[MAXN], top[MAXN], son[MAXN], fa[MAXN], ID[MAXN], rev[MAXN], tim;
    LL dep[MAXN];
    void dfs1(int x, int _fa) {
        siz[x] = 1; dep[x] = dep[_fa] + 1; fa[x] = _fa;
        ID[x] = ++tim; rev[tim] = x;
        for(auto &to : v[x]) {
            if(to == _fa) continue;
            dfs1(to, x);
            siz[x] += siz[to];
            if(siz[to] > siz[son[x]]) son[x] = to;
        }
    }
    void dfs2(int x, int topf) {
        top[x] = topf;
        if(!son[x]) return ;
        dfs2(son[x], topf);
        for(auto &to : v[x]) {
            if(top[to]) continue;
            dfs2(to, to);
        }
    }
    int LCA(int x, int y) {
        while(top[x] ^ top[y]) {
            if(dep[top[x]] < dep[top[y]]) swap(x, y);
            x = fa[top[x]];
        }
        if(dep[x] < dep[y]) swap(x, y);
        return y;
    }
    LL GetDis(int x, int y) {
        int lca = LCA(x, y);
        return dep[x] + dep[y] - 2 * dep[lca];
    }
    int tot;
    struct Ope {
        int l, r, id, fa, ti;//id所在的根节点是哪个,fa连到了大树哪个节点下面 ti第几次操作 
        bool operator < (const Ope &rhs) const {
            return r < rhs.r;
        }
    }md[MAXN];
    set<Ope> lin;
    int root[SS], si[SS], ls[SS], rs[SS], cnt;
    void insert(int &k, int pre, int l, int r, int v) {
        k = ++cnt; ls[k] = ls[pre]; rs[k] = rs[pre]; si[k] = si[pre] + 1;
        if(l == r) return;
        int mid = (l + r) >> 1;
        if(v <= mid) insert(ls[k], ls[pre], l, mid, v);
        else insert(rs[k], rs[pre], mid + 1, r, v);
    }
    int Query(int tl, int tr, int l, int r, int k) {
        if(l == r) return l;
        int cur = si[ls[tr]] - si[ls[tl]], mid = (l + r) >> 1;
        if(cur >= k) return Query(ls[tl], ls[tr], l, mid, k);
        else return Query(rs[tl], rs[tr], mid + 1, r, k - cur);
    }
    int Kth(int x, int k) {//以x节点为根的子树中第k小的节点 
        int l = ID[x], r = ID[x] + siz[x] - 1;
        int tmp = Query(root[l - 1], root[r], 1, N, k);
        //printf("%d %d %d
    ", x, k, tmp);
        return tmp;
    }
    Pair GetId(int x) {//大树中编号为x节点对应的小树中的节点编号,以及该节点被加入的时间 
        Ope nl = *lin.lower_bound((Ope){0, x, 0, 0, 0});
        return {Kth(nl.id, x - nl.l + 1), nl.ti};
    }
    vector<int> V[MAXN];
    int Fa[MAXN][B + 1];
    LL Dep[MAXN], Dis[MAXN][B + 1], t[MAXN][B + 1];
    void Dfs(int x, int fa) {
        Dep[x] = Dep[fa] + 1;
        for(auto &to : V[x]) {
            if(to == fa) continue;
            Dfs(to, x);
        }
    }
    void Pre() {
        for(int j = 1; j <= B; j++)
            for(int i = 1; i <= M; i++) {
                Fa[i][j] = Fa[Fa[i][j - 1]][j - 1];
                t[i][j] = t[Fa[i][j - 1]][j - 1];
                Dis[i][j] = Dis[i][j - 1] + Dis[Fa[i][j - 1]][j - 1];
            }
    }
    LL calc(int x) {//计算大树中编号为x的节点到所在大节点的根的距离 
        Pair tmp = GetId(x);
        return dep[tmp.fi] - dep[md[tmp.se].id];
    }
    LL Query(LL x, LL y) {//大树中编号为x, y的节点的距离 
        Pair bx = GetId(x), by = GetId(y);
        if(bx.se == by.se) return GetDis(bx.fi, by.fi);
        LL prex = x, prey = y, gx, gy;
        x = bx.se; y = by.se; 
        if(Dep[x] < Dep[y]) swap(x, y), swap(prex, prey);
        LL ans = calc(prex);
        for(int i = B; ~i; i--)
            if(Dep[Fa[x][i]] >= Dep[y]) {
                if(Fa[x][i] == y) {
                    gx = GetId(t[x][i]).fi;
                    gy = GetId(prey).fi;
                    return ans + Dis[x][i] + GetDis(gx, gy) - (dep[gx] - dep[md[Fa[x][i]].id]);
                }
                ans += Dis[x][i], x = Fa[x][i];
            }
    //	if(x == y) return ans - 2 * calc(prey); 
        for(int i = B; ~i; i--)
            if(Fa[x][i] != Fa[y][i]) {
                ans += Dis[x][i]; ans += Dis[y][i];
                x = Fa[x][i], y = Fa[y][i];
            }
        gx = GetId(md[x].fa).fi, gy = GetId(md[y].fa).fi;
        return ans + 2 + GetDis(gx, gy) + calc(prey);
    }
    signed main() {
        //freopen("tree13.in", "r", stdin);freopen("b.out", "w", stdout);
        N = read(); M = read() + 1; Q = read();
        for(int i = 1; i <= N - 1; i++) {
            int x = read(), y = read();
            v[x].push_back(y);
            v[y].push_back(x);
        }	
        dfs1(1, 0);
        dfs2(1, 1);//树剖 
        for(int i = 1; i <= N; i++) insert(root[i], root[i - 1], 1, N, rev[i]);
        md[1] = {1, siz[1], 1, 0, 1};
        lin.insert(md[1]);
        tot = siz[1] + 1;
        for(int i = 2; i <= M; i++) {
            int x = read(), to = read();
            md[i] = {tot, tot + siz[x] - 1, x, to, i};
            lin.insert(md[i]);
            tot += siz[x];
        }
        for(int i = 2; i <= M; i++) {
            Ope x = md[i];
            int u = x.ti, v = GetId(x.fa).se;//大树以操作次序来标号 
            V[v].push_back(u);
            Dis[u][0] = dep[GetId(md[u].fa).fi] - dep[md[v].id] + 1;
            Fa[u][0] = v;
            t[u][0]  = md[u].fa;
        }
        Dfs(1, 0);
        Pre();
        
        while(Q--) {
            LL x = read(), y = read();
            cout << Query(x, y) << '
    ';
        }
        return 0;	
    }
    
  • 相关阅读:
    【scala】定义变量和函数
    【python】self用法详解
    【Hive】自定义函数
    【Java】抽象类和接口
    Linux中的wheel用户组是什么?
    CentOS6.9切换root用户su root输入正确密码后一直提示Incorrect password,如何解决?
    CentOS7.X中使用yum安装nginx的方法
    Win10提示“因为文件共享不安全,所以你不能连接到文件共享”如何处理
    vim编辑器-多行加注释与去注释
    CentOS7.4用yum安装并配置MySQL5.7
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/10354804.html
Copyright © 2011-2022 走看看