设为首页 加入收藏

TOP

洛谷P3248 [HNOI2016]树(主席树 倍增 )(一)
2019-02-07 16:08:06 】 浏览:110
Tags:洛谷 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\n", 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  
		
编程开发网
首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇BZOJ2956: 模积和(数论分块) 下一篇数据结构(栈和队列)