线段树合并训练记录

[POI2011]ROT-Tree Rotations

#include <cstdio>
#include <algorithm>
#include <queue>
#include <stack>
#include <string>
#include <string.h>
#include <map>
#include <iostream>
using namespace std;
const int maxn = 4e6 + 50;
const int mod = 20090717;
typedef long long LL;
int INF = 1e9;
typedef pair<int, int> pii;
#define fi first
#define se second
int n;
struct node
{
    int lc, rc;
    LL val;
} tree[maxn];

int tot = 1;
int Build(){
    tot++;
    tree[tot].lc = tree[tot].rc = 0;
    tree[tot].val = 0;
    return tot;
}

int insert(int le, int ri, int pos){
    tree[++tot].val = 1;
    if(le == ri){
        return tot;
    }
    int mid = (le + ri) >> 1;
    int rt = tot;
    if(pos <= mid) tree[rt].lc = insert(le, mid, pos);
    else tree[rt].rc = insert(mid + 1, ri, pos);
    return rt;
}

LL ans, ans1, ans2;
int merage(int le, int ri, int u, int v){
    if(!u || !v) return u | v;
    if(le == ri) {
        tree[u].val += tree[v].val;
        return u;
    }
    int mid = (le + ri) >> 1;
    ans1 += tree[tree[u].lc].val * tree[tree[v].rc].val;
    ans2 += tree[tree[u].rc].val * tree[tree[v].lc].val;

    tree[u].lc = merage(le, mid, tree[u].lc, tree[v].lc);
    tree[u].rc = merage(mid + 1, ri, tree[u].rc, tree[v].rc);
    tree[u].val = tree[tree[u].lc].val + tree[tree[u].rc].val; 
    return u; 
}

int dfs(){
    int u;
    scanf("%d", &u);
    if(u) return insert(1, n, u);
    int rt = merage(1, n, dfs(), dfs());
    // printf("ans1 = %I64d ans2 = %I64d\n", ans1, ans2);
    ans += min(ans1, ans2);
    ans1 = ans2 = 0;
    return rt;
}
int main(int argc, char const *argv[])
{
    scanf("%d", &n);
    dfs();
    printf("%lld\n", ans);
    return 0;
}

洛谷:P4556 [Vani有约会]雨天的尾巴
题解:树上差分 + 线段树合并

#include <cstdio>
#include <algorithm>
#include <queue>
#include <stack>
#include <string>
#include <string.h>
#include <map>
#include <iostream>
#include <math.h>
using namespace std;
const int maxn = 6e6 + 50;
const int mod = 20090717;
typedef long long LL;
int INF = 1e9;
typedef pair<int, int> pii;
#define fi first
#define se second
int n, m;
int nn = 1e5 + 50;
struct node
{
    int lc, rc;
    int val;
} tree[maxn];

vector<int> vec[maxn], vec2[maxn];
int tot;
int Build(){
    tot++;
    tree[tot].lc = tree[tot].rc = 0;
    tree[tot].val = 0;
    return tot;
}

int root[maxn];
int insert(int le, int ri, int pos, int val, int rt){
    if(le == ri){
        tree[rt].val += val;
        return rt;
    }
    int mid = (le + ri) >> 1;

    if(pos <= mid) {
        if(tree[rt].lc == 0) tree[rt].lc = Build();
        tree[rt].lc = insert(le, mid, pos, val, tree[rt].lc);
    }
    else {
        if(tree[rt].rc == 0) tree[rt].rc = Build();
        tree[rt].rc = insert(mid + 1, ri, pos, val, tree[rt].rc);
    }
    tree[rt].val = max(tree[tree[rt].lc].val, tree[tree[rt].rc].val);
    return rt;
}

int merage(int le, int ri, int u, int v){
    if(!u || !v) return u | v;
    if(le == ri) {
        tree[u].val += tree[v].val;
        return u;
    }
    int mid = (le + ri) >> 1;
    tree[u].lc = merage(le, mid, tree[u].lc, tree[v].lc);
    tree[u].rc = merage(mid + 1, ri, tree[u].rc, tree[v].rc);
    tree[u].val = max(tree[tree[u].lc].val, tree[tree[u].rc].val);
    return u; 
}

int Query(int le, int ri, int rt){
    if(!rt) return 0;
    if(le == ri){
        return le;
    }
    if(tree[rt].val == 0) return 0;
    int mid = (le + ri) >> 1;
    if(tree[tree[rt].lc].val >= tree[tree[rt].rc].val){
        return Query(le, mid, tree[rt].lc);
    } else {
        return Query(mid + 1, ri, tree[rt].rc);
    }
}

struct Edge
{
    int to, next;
} edge[maxn];

int head[maxn], k;
void add(int a, int b){
    edge[k].to = b;
    edge[k].next = head[a];
    head[a] = k++;
}

int ans[maxn];
void dfs(int u, int pre){
    root[u] = Build();
    for(int i = head[u]; i != -1; i = edge[i].next){
        int to = edge[i].to;
        if(to == pre) continue;
        dfs(to, u);
        merage(1, nn, root[u], root[to]);
    }
    if(vec[u].size()){
        int len = vec[u].size();
        for(int i = 0; i < len; i++){
            int val = 1;
            if(vec[u][i] < 0) val = -1;
            insert(1, nn, abs(vec[u][i]), val, root[u]);
        }
    }
    ans[u] = Query(1, nn, root[u]);
}

int fa[maxn][30], depth[maxn];
void dfs2(int u, int pre, int d){
    fa[u][0] = pre, depth[u] = d;
    for(int i = head[u]; i != -1; i = edge[i].next){
        int to = edge[i].to;
        if(to == pre) continue;
        dfs2(to, u, d + 1);
    }
}

void init(int root){
    dfs2(root, 0, 0);
    for(int j = 0; (1 << (j + 1)) < n; j++){
        for(int i = 1; i <= n; i++){
            if(fa[i][j] == 0) fa[i][j + 1] = 0;
            else fa[i][j + 1] = fa[fa[i][j]][j];
        }
    }
}

int LCA(int u, int v){
    if(depth[u] > depth[v]) swap(u, v);
    int temp = depth[v] - depth[u];
    for(int i = 0; (1 << i) <= temp; i++){
        if((1 << i) & temp) v = fa[v][i];
    }
    if(v == u) return u;
    for(int i = log2(n); i >= 0; i--){
        if(fa[u][i] != fa[v][i]){
            u = fa[u][i], v = fa[v][i];
        }
    }
    return fa[u][0];
}
int main(int argc, char const *argv[])
{
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++) head[i] = -1;
    for(int i = 1; i < n; i++){
        int x, y;
        scanf("%d%d", &x, &y);
        add(x, y);
        add(y, x);
    }
    init(1);
    for(int i = 1; i <= m; i++){
        int x, y, z;
        scanf("%d%d%d", &x, &y, &z);
        vec[x].push_back(z);
        vec[y].push_back(z);
        int lcaxy = LCA(x, y);
        vec[lcaxy].push_back(-z);
        vec[fa[lcaxy][0]].push_back(-z);
    }
    dfs(1, 0);
    for(int i = 1; i <= n; i++){
        printf("%d\n", ans[i]);
    }
    return 0;
}

BZOJ 3545. [ONTAK2010]Peaks
题解:并查集 + 线段树合并,每次用线段树维护一个联通块
注:由于存在相同高度,所以要合并的两颗线段树可能存在相同的叶子节点,所以要对叶子节点特殊处理,否则会 \(wa\) 到爆炸

#include <cstdio>
#include <algorithm>
#include <queue>
#include <stack>
#include <string>
#include <string.h>
#include <map>
#include <iostream>
#include <math.h>
using namespace std;
const int maxn = 1e5 + 50;
const int MA = 1e7 + 50;
const int mod = 20090717;
typedef long long LL;
int INF = 1e9;
typedef pair<int, int> pii;
#define fi first
#define se second
int n, m;
struct node
{
    int lc, rc;
    int val;
} tree[MA];

int a[maxn], lsh[maxn], id[maxn];
int tot;
int root[maxn];

int fa[maxn];
int Find(int x){
    if(x == fa[x]) return x;
    return fa[x] = Find(fa[x]);
}
struct Edge
{
    int u, v, w;
    int id;
    bool operator < (const Edge &r) const{
        return w < r.w;
    }
} edge[5 * maxn], quer[5 * maxn];


void insert(int le, int ri, int pos, int &rt){
    if(!rt) rt = ++tot;
    tree[rt].val = 1;
    if(le == ri) return ;
    int mid = (le + ri) >> 1;
    if(pos <= mid) insert(le, mid, pos, tree[rt].lc);
    else insert(mid + 1, ri, pos, tree[rt].rc);
}

int imerage(int le, int ri, int u, int v){
    if(!u || !v) return u | v;
    if(le == ri) { // 这句一定要加上,否则相同的叶子节点不会合并,因为数据存在相同的高度
        tree[u].val += tree[v].val;
        return u;
    }
    // if(!tree[u].lc && !tree[u].rc){
    //     tree[u].val += tree[v].val;
    //     return u;
    // }
    int mid = (le + ri) >> 1;
    tree[u].lc = imerage(le, mid, tree[u].lc, tree[v].lc);
    tree[u].rc = imerage(mid + 1, ri, tree[u].rc, tree[v].rc);
    tree[u].val = tree[tree[u].lc].val + tree[tree[u].rc].val;
    return u;
}

int Query(int le, int ri, int rt, int sum){
    if(tree[rt].val < sum) return 0;
    if(le == ri) return le;
    int mid = (le + ri) >> 1;
    if(tree[tree[rt].rc].val >= sum) {
        return Query(mid + 1, ri, tree[rt].rc, sum);
    } else {
        return Query(le, mid, tree[rt].lc, sum - tree[tree[rt].rc].val);
    }
}
int ans[5 * maxn];
int main(int argc, char const *argv[])
{
    int q;
    scanf("%d%d%d", &n, &m, &q);
    for(int i = 1; i <= n; i++){
        fa[i] = i;
        scanf("%d", &a[i]);
        lsh[i] = a[i];
    }

    sort(lsh + 1, lsh + n + 1);
    int cnt;
    for(int i = 1; i <= n; i++){
        a[i] = lower_bound(lsh + 1, lsh + n + 1, a[i]) - lsh;
    }

    for(int i = 1; i <= m; i++){
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        edge[i] = {u, v, w, 0};
    }
    for(int i = 1; i <= q; i++){
        int u, x, k;
        scanf("%d%d%d", &u, &x, &k);
        quer[i] = {u, k, x, i};
    }

    sort(edge + 1, edge + m + 1);
    sort(quer + 1, quer + q + 1);
    cnt = 1;

    for(int i = 1; i <= n; i++) insert(1, n, a[i], root[i]);
    lsh[0] = -1;
    for(int i = 1; i <= q; i++){
        while(edge[cnt].w <= quer[i].w && cnt <= m){
            int u = edge[cnt].u, v = edge[cnt].v;
            u = Find(u), v = Find(v); // 这里写成fa[u], fa[v] 会MLE
            if(u == v){
                cnt++;
                continue;
            }
            imerage(1, n, root[u], root[v]);
            fa[v] = u;
            cnt++;
        }
        int u = quer[i].u;
        u = Find(u);
        int res = Query(1, n, root[u], quer[i].v);
        ans[quer[i].id] = lsh[res];
    }
    for(int i = 1; i <= q; i++){
        printf("%d\n", ans[i]);
    }
    return 0;
}
posted @ 2020-07-24 14:55  从小学  阅读(126)  评论(0编辑  收藏  举报