笛卡尔树及克鲁斯卡尔重构树

笛卡尔树

好东西, 可以用于最大(小)值分治, 在\(O(n)\)的时间复杂度内建出一个节点为区间最大值的树, 每次分治时走小区间可以保证\(O(nlog_n)\)的复杂度

建树时维护极右链, 他的中序遍历即原序列

代码


#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,v[N],fa[N],ls[N],rs[N];
int s[N],top;
void Tree()
{
    for(int i = 1; i <= n; i ++)
    {
        scanf("%d",&v[i]);
        while(top && v[s[top]] > v[i])
        ls[i] = s[top], top --;
        fa[i] = s[top];
        fa[ls[i]] = i;
        if(fa[i]) rs[fa[i]] = i;
        s[++ top] = i;
    }
}

克鲁斯卡尔重构树

就像跑最小生成树一般, 只是每次合并时新建一个节点t, 让它与两个连通块的代表点连边, t成为整个连通块的代表节点, 这样保证底下的边权小于上面的边权

最小瓶颈生成树:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#define ll long long
using namespace std;
const int N = 1005000;
const int fP = 1e9+7;
vector <int> v[N];
template <typename T>
void read(T &x) {
    x = 0; bool f = 0;
    char c = getchar();
    for (;!isdigit(c);c=getchar()) if (c=='-')f=1;
    for (;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c^48);
    if (f) x=-x;
}
int n, m, p;
int val[N], f[N], cnt;
int A, B, C, P, q;
int st[N][20], fir[N];
int find(int x) {
    if (x == f[x]) return x;
    return f[x] = find(f[x]);
}
struct node{
    int x, y, w;
    bool operator < (const node &i) const {
        return w < i.w;
    }
}ed[N];
inline int rnd() {
    return A = (A * B + C) % P;
}
ll a[N], ans, tot;
void dfs(int x) {
    a[++tot] = val[x], fir[x] = tot;
    for (int i = 0;i < v[x].size(); i++) {
        int y = v[x][i];
        dfs(y); a[++tot] = val[x];
    }
}
int lg[N], s, t;
void init(void) {
    lg[0] = -1;
    for (int i = 1;i <= tot; i++)
        st[i][0] = a[i], lg[i] = lg[i>>1] + 1;
    for (int len = 1; (1 << len) <= tot; len++)
        for (int l = 1;l + (1 << len) - 1 <= tot; l++)
             st[l][len] = max(st[l][len-1], st[l + (1<<(len-1))][len-1]);
}

int ask(int l,int r) {
    if (l > r) swap(l, r);
    int t = lg[r - l + 1];
    return max(st[l][t], st[r-(1<<t)+1][t]);
}

int main() {
    read(n), read(m); cnt = n;
    for (int i = 1;i <= n*2; i++) f[i] = i;
    for (int i = 1;i <= m; i++)
        read(ed[i].x), read(ed[i].y), read(ed[i].w);
    sort(ed + 1,ed + m + 1);
    for (int i = 1;i <= m; i++) {
        int fx = find(ed[i].x), fy = find(ed[i].y);
        if (fx == fy) continue;
        val[++cnt] = ed[i].w;
        v[cnt].push_back(fy); v[cnt].push_back(fx);
        f[fx] = f[fy] = cnt;
    }
    dfs(cnt); init();
    read(q); read(A), read(B), read(C), read(P);
    while (q--) {
        s = rnd() % n + 1, t = rnd() % n + 1;
        ans += ask(fir[s], fir[t]);
        if (ans > fP) ans -= fP;
    }
    cout << ans % fP << endl;
    return 0;
}

原文地址:https://www.cnblogs.com/Hs-black/p/12271678.html

时间: 2024-10-15 15:38:38

笛卡尔树及克鲁斯卡尔重构树的相关文章

hdu 5412 CRB and Queries(线段树套笛卡尔树 - 动态区间第k大)

题目链接:hdu 5412 CRB and Queries 首先对所有出现过的值排序,建立线段树,每个线段树的节点是一棵笛卡尔树,笛卡尔树记录区间下标值. #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using namespace std; #define lson(x) (x<<1) #define rson(x) ((x<<

笛卡尔树cartesian tree

笛卡尔树cartesian tree 笛卡尔树是一种特定的二叉树数据结构,可由数列构造,在范围最值查询.范围top k查询(range top k queries)等问题上有广泛应用.它具有堆的有序性,中序遍历可以输出原数列.笛卡尔树结构由Vuillmin(1980)[1]在解决范围搜索的几何数据结构问题时提出.从数列中构造一棵笛卡尔树可以线性时间完成,需要采用基于栈的算法来找到在该数列中的所有最近小数. 定义 无相同元素的数列构造出的笛卡尔树具有下列性质: 结点一一对应于数列元素.即数列中的每

POJ-2201-Cartesian Tree(笛卡尔树)

Description Let us consider a special type of a binary search tree, called a cartesian tree. Recall that a binary search tree is a rooted ordered binary tree, such that for its every node x the following condition is satisfied: each node in its left

[COGS 2421] [HZOI 2016] 简单的Treap 笛卡尔树

笛卡尔树就是你给两维限制,一维堆R,一维二叉搜索树K,平地拔起一棵Treap,最广范的应用:用LCA求区间最值,建Treap,还有个什么范围top k我表示并不会查都查不到.它最妙最高的地方在于用栈来建树:我们可以先排序K然后一个个插入,那么我们都是最右端,横容易被卡,那么我们不从上到下,我们从下到上,用栈维护,那就把时间复杂度从O(n^2)降到O(n),具体过程见下图从图一到图二就是这么一个过程,我们在把K为13的点插入时要找到一个合适的位置,上比他大,下比他小(假设大根堆) 下面见代码 #i

POJ 2559 Largest Rectangle in a Histogram ——笛卡尔树

[题目分析] 本来是单调栈的题目,用笛卡尔树可以快速的水过去. 把每一个矩阵看成一个二元组(出现的顺序,高度). 然后建造笛卡尔树. 神奇的发现,每一个节点的高度*该子树的大小,就是这一块最大的子矩阵的可能解. 用二元组的第一个下标来限制,使它们在一块儿,然后堆的性质又限制了宽度以及高度. 计算,取最值即可. [代码] #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath&g

POJ-1785-Binary Search Heap Construction(笛卡尔树)

Description Read the statement of problem G for the definitions concerning trees. In the following we define the basic terminology of heaps. A heap is a tree whose internal nodes have each assigned a priority (a number) such that the priority of each

NOIP2011pj表达式的值[树形DP 笛卡尔树]

题目描述 对于1 位二进制变量定义两种运算: 运算的优先级是: 先计算括号内的,再计算括号外的. “× ”运算优先于“⊕”运算,即计算表达式时,先计算× 运算,再计算⊕运算.例如:计算表达式A⊕B × C时,先计算 B × C,其结果再与 A 做⊕运算. 现给定一个未完成的表达式,例如+(*_),请你在横线处填入数字0 或者1 ,请问有多少种填法可以使得表达式的值为0 . 输入输出格式 输入格式: 输入文件名为exp.in ,共 2 行. 第1 行为一个整数 L,表示给定的表达式中除去横线外的运

4-09. 笛卡尔树(25)(ZJU_PAT)

题目链接:http://www.patest.cn/contests/ds/4-09 笛卡尔树是一种特殊的二叉树,其结点包含两个关键字K1和K2.首先笛卡尔树是关于K1的二叉搜索树,即结点左子树的所有K1值都比该结点的K1值小,右子树则大.其次所有结点的K2关键字满足优先队列(不妨设为最小堆)的顺序要求,即该结点的K2值比其子树中所有结点的K2值小.给定一棵二叉树,请判断该树是否笛卡尔树. 输入格式说明: 输入首先给出正整数N(<=1000),为树中结点的个数.随后N行,每行给出一个结点的信息,

笛卡尔树 POJ ——1785 Binary Search Heap Construction

相应POJ 题目:点击打开链接 Binary Search Heap Construction Time Limit: 2000MS   Memory Limit: 30000K Total Submissions: 9075   Accepted: 2566 Description Read the statement of problem G for the definitions concerning trees. In the following we define the basic