BZOJ 4539|HNOI 2016|树|可持久化线段树|LCA ******

75 篇文章 1 订阅
15 篇文章 0 订阅

被虐惨了QwQ
下面的程序只是备份并不是最终代码QwQ
连编译器都怕了我的代码QwQ
编译时间长于5s QwQ

#include <cstdio>
#include <algorithm>
#define FOR(i,j,k) for(int i=j;i<=k;++i)
using namespace std;
const int N = 200005, M = N * 2, K = 19;
typedef long long ll;
ll read() {
    ll x = 0, f = 1; char ch = getchar();
    for (; ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') x = x * 10 + ch - '0';
    for (; '0' <= ch && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
    return x * f;
}
struct Seg {
    Seg *lc, *rc; int sz;
    Seg() { lc = rc = this; sz = 0; }
    Seg(Seg *_lc, Seg *_rc, int _sz) :
        lc(_lc), rc(_rc), sz(_sz) { }
    void *operator new(size_t) {
        static Seg p[M * 30], *C = p;
        return C++;
    }
    Seg *put(int l, int r, int x) {
        int mid = l + r >> 1;
        if (l == r) return new Seg(0, 0, sz + 1);
        else if (x <= mid) return new Seg(lc->put(l, mid, x), rc, sz + 1);
        else return new Seg(lc, rc->put(mid + 1, r, x), sz + 1);
    }
    static int get(Seg *x, Seg *y, int l, int r, int k) {
        int mid = l + r >> 1;
        if (l == r) return l;
        if (k <= y->lc->sz - x->lc->sz) return get(x->lc, y->lc, l, mid, k);
        else return get(x->rc, y->rc, mid + 1, r, k - (y->lc->sz - x->lc->sz));
    }
} *tree[N];
int n;
int query(int x, int y, int k) {
    return Seg::get(tree[x - 1], tree[y], 1, n, k);
}
struct Tree {
    int h[N], p[M], v[M], cnt, fa[N][20];
    int pos[N], end[N], dep[N], id, sz[N];
    ll w[M], dis[N];
    void add(int a, int b, ll c) {
        p[++cnt] = h[a]; v[cnt] = b; w[cnt] = c; h[a] = cnt;
        p[++cnt] = h[b]; v[cnt] = a; w[cnt] = c; h[b] = cnt;
    }
    void dfs(int x, int f, ll d) {
        fa[x][0] = f; dep[x] = dep[f] + 1; dis[x] = d;
        FOR(i,1,K) fa[x][i] = fa[fa[x][i - 1]][i - 1];
        for (int i = h[x]; i; i = p[i])
            if (v[i] != f) dfs(v[i], x, d + w[i]);
    }
    void dfs2(int x) {
        sz[x] = 1; pos[x] = ++id; tree[id] = tree[id - 1]->put(1, n, x);
        for (int i = h[x]; i; i = p[i])
            if (v[i] != fa[x][0])
                dfs2(v[i]), sz[x] += sz[v[i]];
        end[x] = id;
    }
    int jump(int x, int d) {
        FOR(i,0,K) if ((1 << i) & d) x = fa[x][i];
        return x;
    }
    int lca(int x, int y) {
        if (dep[x] < dep[y]) swap(x, y);
        jump(x, dep[x] - dep[y]);
        for(int i=K;i>=0;--i) if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
        return x == y ? x : fa[x][0];
    }
    ll dist(int x, int y) {
        return dis[x] + dis[y] - 2 * dis[lca(x, y)];
    }
    int belong(int u, int v) {
        return jump(u, dep[u] - dep[v] - 1);
    }
} o, g;
int rt[N], belong[N], idx; ll cnt[N], nn;
int id(ll x) { return lower_bound(cnt + 1, cnt + 1 + idx, x) - cnt; }
ll query(ll a, ll b) {
    ll A = a, B = b;
    a = id(a); b = id(b);
    int c = g.lca(a, b);
    int ra = rt[a], rb = rt[b];
    int aa = query(o.pos[ra], o.end[ra], A - cnt[a - 1]);
    int bb = query(o.pos[rb], o.end[rb], B - cnt[b - 1]);
    if (a == b) return o.dist(aa, bb);
    ll ans = g.dist(a, b) + o.dis[aa] - o.dis[ra] + o.dis[bb] - o.dis[rb];
    int fa = belong[g.belong(a, c)], fb = belong[g.belong(b, c)];
    if (a == c) ans -= o.dis[aa] + o.dis[fb] - o.dist(aa, fb) - 2ll * o.dis[ra];
    else if (b == c) ans -= o.dis[bb] + o.dis[fa] - o.dist(bb, fa) - 2ll * o.dis[rb];
    else ans -= o.dis[fa] + o.dis[fb] - o.dist(fa, fb) - 2ll * o.dis[rt[c]];
    return ans;
}
int main() {
    int a, b, m, q, x, t;
    n = read(); m = read(); q = read();
    tree[0] = new Seg();
    FOR(i,2,n) o.add(read(), read(), 1);
    o.dfs(1, 0, 0); o.dfs2(1);
    nn = n; cnt[1] = nn; rt[1] = idx = 1;
    FOR(i,2,m+1) {
        a = read(); b = read();
        x = id(b); t = rt[x];
        rt[i] = a; idx = i; belong[i] = query(o.pos[t], o.end[t], b - cnt[x - 1]);
        g.add(i, x, o.dis[belong[i]] - o.dis[t] + 1);
        nn += o.sz[a]; cnt[i] = nn;
    }
    g.dfs(1, 0, 0);
    while (q--) printf("%lld\n", query(read(), read()));
    return 0;
}

4539: [Hnoi2016]树

Description

  小A想做一棵很大的树,但是他手上的材料有限,只好用点小技巧了。开始,小A只有一棵结点数为N的树,结
点的编号为1,2,…,N,其中结点1为根;我们称这颗树为模板树。小A决定通过这棵模板树来构建一颗大树。构建过
程如下:(1)将模板树复制为初始的大树。(2)以下(2.1)(2.2)(2.3)步循环执行M次(2.1)选择两个数字a,b,
其中1<=a<=N,1<=b<=当前大树的结点数。(2.2)将模板树中以结点a为根的子树复制一遍,挂到大树中结点b的下
方(也就是说,模板树中的结点a为根的子树复制到大树中后,将成为大树中结点b的子树)。(2.3)将新加入大树
的结点按照在模板树中编号的顺序重新编号。例如,假设在进行2.2步之前大树有L个结点,模板树中以a为根的子
树共有C个结点,那么新加入模板树的C个结点在大树中的编号将是L+1,L+2,…,L+C;大树中这C个结点编号的大小
顺序和模板树中对应的C个结点的大小顺序是一致的。下面给出一个实例。假设模板树如下图:

根据第(1)步,初始的大树与模板树是相同的。在(2.1)步,假设选择了a=4,b=3。运行(2.2)和(2.3)后,得到新的

大树如下图所示

现在他想问你,树中一些结点对的距离是多少。

Input

  第一行三个整数:N,M,Q,以空格隔开,N表示模板树结点数,M表示第(2)中的循环操作的次数,Q 表示询问数
量。接下来N-1行,每行两个整数 fr,to,表示模板树中的一条树边。再接下来M行,每行两个整数x,to,表示将模
板树中 x 为根的子树复制到大树中成为结点to的子树的一次操作。再接下来Q行,每行两个整数fr,to,表示询问
大树中结点 fr和 to之间的距离是多少。

Output

  输出Q行,每行一个整数,第 i行是第 i个询问的答案。

Sample Input

5 2 3 
1 4 
1 3 
4 2 
4 5 
4 3 
3 2 
6 9 
1 8 
5 3 

Sample Output

6
3
3

HINT

经过两次操作后,大树变成了下图所示的形状:

结点6到9之间经过了6条边,所以距离为6;类似地,结点1到8之间经过了3条边;结点5到3之间也经过了3条边。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值