P4197 Peaks【Kruskal重构树上dfs序跑时间戳建可持久化线段树】

题目链接


  怎么说呢,虽然码量有点长,但是一遍调过还是很开森的哈哈哈哈哈哈哈!嗝~~~

  首先“困难值小于等于 x 的路径”,那么,其实就是Kruskal重构树的暗示了,之后又不带边权的修改,那么更显然是Kruskal重构树了!然后就是树上不带修改的询问第K大,其实就是暗示着主席树了,所以这里必须是要去建可持久化线段树的。

  然后就是树上跑可持久化线段树的问题了,之前试过了启发式合并,但是很没有办法会TLE,那么,我们就得去试着用别的方法,一种很显然的手段就是dfs序跑出来的时间戳来建可持久化线段树了。这里我们可以知道,所有的原树上的结点一定会是重构树的叶子结点,那么,其余的新构结点我们就不给他们dfs序,给他们的是他的子树的dfs序的区间岂不是更好,节约空间。

  那么,在一棵树上的问题就解决了,但是题目中并没有说原图联通,所以,在这里引入超级源点,对于所有的树的根结点连接到超级源点上去,于是就把森林重新变成了一棵树,我们再来跑这样的操作就可以完成上述的任务了。

  其实,想想还是很简单的,实现起来也不是太难,debug就是了。

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
//#include <unordered_map>
//#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
//#define INF 10000007.
#define eps 1e-7
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 2e5 + 7, maxM = 5e5 + 7;
int N, M, Q, h[maxN], lsan[maxN], _UP, root[maxN], head[maxN], cnt, ex_N, W[maxN];
int fid(int x) { return x == root[x] ? x : root[x] = fid(root[x]); }
struct Graph
{
    int u, v, w;
    inline void In_Put() { scanf("%d%d%d", &u, &v, &w); }
    friend bool operator < (Graph e1, Graph e2) { return e1.w < e2.w; }
} E[maxM];
struct Eddge
{
    int nex, to;
    Eddge(int a=-1, int b=0):nex(a), to(b) {}
}edge[maxN];
inline void addEddge(int u, int v)
{
    edge[cnt] = Eddge(head[u], v);
    head[u] = cnt++;
}
struct Endless_Tree
{
    int root[maxN], tot, tree[30 * maxN], lc[30 * maxN], rc[30 * maxN];
    inline void clear() { root[0] = 0; tot = 0; tree[0] = lc[0] = rc[0] = 0; }
    inline void pushup(int rt) { tree[rt] = tree[lc[rt]] + tree[rc[rt]]; }
    void update(int &now, int old, int l, int r, int qx)
    {
        now = ++tot;
        tree[now] = tree[old] + 1; lc[now] = lc[old]; rc[now] = rc[old];
        if(l == r) return;
        int mid = HalF;
        if(qx <= mid) update(lc[now], lc[old], l, mid, qx);
        else update(rc[now], rc[old], mid + 1, r, qx);
    }
    int query(int root_L, int root_R, int l, int r, int kth)
    {
        if(l == r) return l;
        int mid = HalF;
        if(tree[rc[root_R]] - tree[rc[root_L]] >= kth) return query(rc[root_L], rc[root_R], mid + 1, r, kth);
        else return query(lc[root_L], lc[root_R], l, mid, kth - (tree[rc[root_R]] - tree[rc[root_L]]));
    }
    int Range_check(int L, int R, int kth) { return query(root[L - 1], root[R], 1, _UP, kth); }
} ET;
pair<int, int> each_new_id[maxN];   //每个重构点的左右区间(dfs序)
struct dfs_ID
{
    int dfn[maxN], tot, fa[maxN][20], deep[maxN];
    void clear() { tot = 0; }
    void dfs(int u)
    {
        if(u > N) each_new_id[u].first = tot + 1;
        else
        {
            dfn[u] = ++tot;
            ET.update(ET.root[tot], ET.root[tot - 1], 1, _UP, h[u]);
        }
        for(int i=0; (1 << (i + 1)) < N; i++) fa[u][i + 1] = fa[fa[u][i]][i];
        for(int i=head[u], v; ~i; i=edge[i].nex)
        {
            v = edge[i].to;
            fa[v][0] = u; deep[v] = deep[u] + 1;
            dfs(v);
        }
        if(u > N) each_new_id[u].second = tot;
    }
} dfs_id;
inline void init()
{
    cnt = 0; ex_N = N;
    for(int i = 1; i <= N << 1; i++)
    {
        head[i] = -1;
        root[i] = i;
    }
}
int LOG[maxN];
inline void Pre()
{
    for(int i = 1, j = 0, nex = 2; i<maxN; i++)
    {
        if(i == nex) { j++; nex <<= 1; }
        LOG[i] = j;
    }
}
int main()
{
    Pre();
    scanf("%d%d%d", &N, &M, &Q);
    init();
    for(int i=1; i<=N; i++) { scanf("%d", &h[i]); lsan[i] = h[i]; }
    sort(lsan + 1, lsan + N + 1);
    _UP = (int)(unique(lsan + 1, lsan + N + 1) - lsan - 1);
    for(int i=1; i<=N; i++) h[i] = (int)(lower_bound(lsan + 1, lsan + _UP + 1, h[i]) - lsan);
    for(int i=1; i<=M; i++) E[i].In_Put();
    sort(E + 1, E + M + 1);
    for(int i=1, fu, fv; i<=M; i++)
    {
        fu = fid(E[i].u); fv = fid(E[i].v);
        if(fu ^ fv)
        {
            ex_N ++; W[ex_N] = E[i].w;
            addEddge(ex_N, fu); addEddge(ex_N, fv);
            root[fu] = root[fv] = ex_N;
        }
    }
    ex_N++; W[ex_N] = INF;
    for(int i=1; i<ex_N; i++)   //存在森林的情况,我们需要拉出来考虑,现在重构树的根结点就是ex_N
    {
        if(fid(i) == i)
        {
            addEddge(ex_N, i);
        }
    }
    ET.clear();
    dfs_id.clear();
    dfs_id.deep[ex_N] = 0;
    dfs_id.dfs(ex_N);
    int u, v, x, k, siz;
    while(Q--)
    {
        scanf("%d%d%d", &v, &x, &k);
        u = v;
        for(int i=LOG[dfs_id.deep[u]]; i>=0; i--)
        {
            if(!dfs_id.fa[u][i]) continue;
            if(W[dfs_id.fa[u][i]] <= x)
            {
                u = dfs_id.fa[u][i];
            }
        }
        if(u == v)
        {
            if(k == 1) printf("%d\n", lsan[h[v]]);
            else printf("-1\n");
            continue;
        }
        siz = each_new_id[u].second - each_new_id[u].first + 1;
        if(siz < k) { printf("-1\n"); continue; }
        printf("%d\n", lsan[ET.Range_check(each_new_id[u].first, each_new_id[u].second, k)]);
    }
    return 0;
}
发布了770 篇原创文章 · 获赞 927 · 访问量 8万+

猜你喜欢

转载自blog.csdn.net/qq_41730082/article/details/104128975