bzoj3545 Peaks 线段树合并

离线乱搞。。。
也就是一个线段树合并没什么

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>

using namespace std;

int n,m,q,tot,cnt,num,h[100001],a[100001],ans[500001],fa[100001],root[100001];

struct edge{
    int u,v,cost;
    bool operator < (const edge &b) const{
        return cost<b.cost;
    }
}e[500001];

struct Que{
    int id,v,x,k;
    bool operator < (const Que &b) const{
        return x<b.x;
    }
}que[500001];

struct node{
    int lch,rch,siz;
}tree[2000001];

int find(int x){
    if(fa[x]==x)return x;
    return fa[x]=find(fa[x]);
}

void insert(int o,int l,int r,int x){
    tree[o].siz++;
    if(l==r)return;
    int mid=(l+r)>>1;
    if(x<=mid){
        if(!tree[o].lch)tree[o].lch=++num;
        insert(tree[o].lch,l,mid,x);
    }
    if(x>mid){
        if(!tree[o].rch)tree[o].rch=++num;
        insert(tree[o].rch,mid+1,r,x);
    }
}

int query(int o,int l,int r,int k){
    if(k<=0 or k>tree[o].siz)return -1;
    if(l==r)return l;
    int mid=(l+r)>>1;
    if(k<=tree[tree[o].lch].siz)return query(tree[o].lch,l,mid,k);
    return query(tree[o].rch,mid+1,r,k-tree[tree[o].lch].siz);
}

int merge(int x,int y){
    if(!x or !y)return x+y;
    tree[x].siz+=tree[y].siz;
    tree[x].lch=merge(tree[x].lch,tree[y].lch);tree[x].rch=merge(tree[x].rch,tree[y].rch);
    return x;
}

int main(){
    scanf("%d%d%d",&n,&m,&q);
    for(int i=1;i<=n;i++){
        scanf("%d",&h[i]);
        a[i]=h[i];fa[i]=i;
    }
    sort(a+1,a+n+1);
    for(int i=1;i<=n;i++)h[i]=lower_bound(a+1,a+n+1,h[i])-a;
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].cost);
    }
    sort(e+1,e+m+1);
    for(int i=1;i<=q;i++){
        scanf("%d%d%d",&que[i].v,&que[i].x,&que[i].k);que[i].id=i;
    }

    for(int i=1;i<=n;i++){
        fa[i]=i;
        root[i]=++num;
        insert(root[i],1,n,h[i]);
    }
    sort(que+1,que+q+1);
    for(int i=1;i<=q;i++){
        while(cnt<m and e[cnt+1].cost<=que[i].x){
            int fx=find(e[++cnt].u);
            int fy=find(e[cnt].v);
            if(fx==fy)continue;
            fa[fx]=fy;
            root[fy]=merge(root[fx],root[fy]);
        }
        int rot=root[find(que[i].v)],ret=query(rot,1,n,tree[rot].siz-que[i].k+1);
        ans[que[i].id]=~ret?a[ret]:ret;
    }
    for(int i=1;i<=q;i++){
        printf("%d\n",ans[i]);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/ezoihy/p/9482014.html

时间: 2024-09-30 10:07:36

bzoj3545 Peaks 线段树合并的相关文章

【bzoj3545】[ONTAK2010]Peaks 线段树合并

[bzoj3545][ONTAK2010]Peaks 2014年8月26日3,1512 Description 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达的山峰中第k高的山峰,如果无解输出-1. Input 第一行三个数N,M,Q.第二行N个数,第i个数为h_i接下来M行,每行3个数a b c,表示从a到b有一条困难

[BZOJ3545] [ONTAK2010]Peaks(线段树合并 + 离散化)

传送门 由于困难值小于等于x这个很恶心,可以离线处理,将边权,和询问时的x排序. 每到一个询问的时候,将边权小于等于x的都合并起来再询问. .. 有重复元素的线段树合并的时间复杂度是nlog^2n #include <cstdio> #include <iostream> #include <algorithm> #define N 500001 int n, m, q, cnt, tot, size; int sum[N * 10], ls[N * 10], rs[N

【线段树合并】bzoj3545: [ONTAK2010]Peaks

1A还行 Description 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达的山峰中第k高的山峰,如果无解输出-1. Input 第一行三个数N,M,Q.第二行N个数,第i个数为h_i接下来M行,每行3个数a b c,表示从a到b有一条困难值为c的双向路径.接下来Q行,每行三个数v x k,表示一组询问. Outpu

【BZOJ4399】魔法少女LJJ 线段树合并

[BZOJ4399]魔法少女LJJ Description 在森林中见过会动的树,在沙漠中见过会动的仙人掌过后,魔法少女LJJ已经觉得自己见过世界上的所有稀奇古怪的事情了LJJ感叹道“这里真是个迷人的绿色世界,空气清新.淡雅,到处散发着醉人的奶浆味:小猴在枝头悠来荡去,好不自在:各式各样的鲜花争相开放,各种树枝的枝头挂满沉甸甸的野果:鸟儿的歌声婉转动听,小河里飘着落下的花瓣真是人间仙境”SHY觉得LJJ还是太naive,一天,SHY带着自己心爱的图找到LJJ,对LJJ说:“既然你已经见识过动态树

【BZOJ2733】永无乡[splay启发式合并or线段树合并]

题目大意:给你一些点,修改是在在两个点之间连一条无向边,查询时求某个点能走到的点中重要度第k大的点.题目中给定的是每个节点的排名,所以实际上是求第k小:题目求的是编号,不是重要度的排名.我一开始差点被这坑了. 网址:http://www.lydsy.com/JudgeOnline/problem.php?id=2733 这道题似乎挺经典的(至少我看许多神犇很早就做了这道题).这道题有两种写法:并查集+(splay启发式合并or线段树合并).我写的是线段树合并,因为--splay不会打+懒得学.

BZOJ 4756 线段树合并(线段树)

思路: 1.最裸的线段树合并 2. 我们可以观察到子树求一个东西 那我们直接DFS序好了 入队的时候统计一下有多少比他大的 出的时候统计一下 减一下 搞定~ 线段树合并代码: //By SiriusRen #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N=100050; int n,col[N],cpy[N],tree[N*100],lso

bzoj2733: [HNOI2012]永无乡(splay+启发式合并/线段树合并)

这题之前写过线段树合并,今天复习Splay的时候想起这题,打算写一次Splay+启发式合并. 好爽!!! 写了长长的代码(其实也不长),只凭着下午的一点记忆(没背板子...),调了好久好久,过了样例,submit,1A! 哇真的舒服 调试输出懒得删了QwQ #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<queue> #include

[XJOI NOI2015模拟题13] C 白黑树 【线段树合并】

题目链接:XJOI - NOI2015-13 - C 题目分析 使用神奇的线段树合并在 O(nlogn) 的时间复杂度内解决这道题目. 对树上的每个点都建立一棵线段树,key是时间(即第几次操作),动态开点. 线段树的节点维护两个值,一个是这段时间内的 1 操作个数,另一个是这段时间内变化的黑色节点权值和. 在处理所有操作的时候,每棵线段树都是仅代表树上的一个点,因此线段树的每个节点维护的就是这段时间内以这个点为 a 的 1 操作个数和这段时间内这个点的黑色节点权值和(这个点 x 由黑变白就 -

[BZOJ 2212] [Poi2011] Tree Rotations 【线段树合并】

题目链接:BZOJ - 2212 题目分析 子树 x 内的逆序对个数为 :x 左子树内的逆序对个数 + x 右子树内的逆序对个数 + 跨越 x 左子树与右子树的逆序对. 左右子树内部的逆序对与是否交换左右子树无关,是否交换左右子树取决于交换后 “跨越 x 左子树与右子树的逆序对” 是否会减小. 因此我们要求出两种情况下的逆序对数,使用线段树合并,对每个节点建一棵线段树,然后合并的同时就求出两种情况下的逆序对. 代码 #include <iostream> #include <cstdli