zoukankan      html  css  js  c++  java
  • BZOJ3545 Peaks 离线处理+线段树合并

    题意:

      在Bytemountains有N座山峰,每座山峰有他的高度h_i。有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达的山峰中第k高的山峰,如果无解输出-1。

    分析:

      我们把题目中的限制分离出来:

      1. 困难值不超过x。

      2. 能达到的第k高的山峰。

      如果没有限制1,我们对每个连通块建线段树即可,如果没有限制2,我们我们可以选择按照kruskal的思想,按照困难值从小到大加便,离线处理询问。

      现在两个限制都在,所以我们考虑使两种算法兼容,所以我们连边时如果两个端点分别属于不同的连通块,我们就合并两个连通块,需要处理的问题是并查集合并和线段树合并。同时离线处理询问即可。

      这题还有一个加强版,是强制在线的版本,应该是一道kruskal重构树的练手题。

    代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int N=100005;
     4 struct que{int a,b,c,id,ok;}a[N*10];
     5 struct seg{int ls,rs,v;}t[N*50];
     6 int n,m,q,tot=0,nm1[N],nm2[N],fa[N],rt[N],ans[N*5];
     7 bool cmp(que a,que b){
     8     return a.c==b.c?a.ok<b.ok:a.c<b.c;
     9 } int get(int x){
    10     return fa[x]==x?x:fa[x]=get(fa[x]);
    11 } void update(int &x,int l,int r,int v){
    12     if(!x) x=++tot;t[x].v=1;
    13     if(l==r) return ;int mid=l+r>>1;
    14     if(v<=mid) update(t[x].ls,l,mid,v);
    15     else update(t[x].rs,mid+1,r,v);
    16 } int query(int x,int l,int r,int p){
    17     if(l==r) return l;int mid=l+r>>1;
    18     if(p<=t[t[x].ls].v) 
    19     return query(t[x].ls,l,mid,p);
    20     else return 
    21     query(t[x].rs,mid+1,r,p-t[t[x].ls].v);
    22 } int merge(int x,int y){
    23     if(!x||!y) return x|y;
    24     if(!t[x].ls&&!t[x].rs){
    25         t[x].v+=t[y].v;return x;
    26     } t[x].ls=merge(t[x].ls,t[y].ls);
    27     t[x].rs=merge(t[x].rs,t[y].rs);
    28     t[x].v=t[t[x].ls].v+t[t[x].rs].v;
    29     return x;
    30 } int main(){
    31     scanf("%d%d%d",&n,&m,&q);
    32     for(int i=1;i<=n;i++)
    33     scanf("%d",&nm1[i]),
    34     nm2[i]=nm1[i],fa[i]=i;
    35     sort(nm2+1,nm2+n+1);
    36     for(int i=1;i<=n;i++)
    37     nm1[i]=lower_bound(nm2+1,nm2+1+n,nm1[i])-nm2;
    38     for(int i=1,x,y,z;i<=m;i++)
    39     scanf("%d%d%d",&x,&y,&z),
    40     a[i]=(que){x,y,z,0,0};
    41     for(int i=m+1,x,y,z;i<=m+q;i++)
    42     scanf("%d%d%d",&x,&y,&z),
    43     a[i]=(que){x,z,y,i-m,1};
    44     sort(a+1,a+1+m+q,cmp);
    45     for(int i=1;i<=n;i++)
    46     update(rt[i],1,n,nm1[i]);
    47     for(int i=1;i<=m+q;i++)
    48     if(!a[i].ok){
    49         int x=get(a[i].a),y=get(a[i].b);
    50         if(x!=y) fa[x]=y,
    51         rt[y]=merge(rt[x],rt[y]);
    52     } else{
    53         int x=get(a[i].a);
    54         if(t[rt[x]].v<a[i].b)
    55         ans[a[i].id]=-1;
    56         else ans[a[i].id]=
    57         nm2[query(rt[x],1,n,t[rt[x]].v-a[i].b+1)];
    58     } for(int i=1;i<=q;i++) 
    59     printf("%d
    ",ans[i]);return 0;
    60 }
    线段树合并
  • 相关阅读:
    CSS 整形与优化工具
    下面是小图,点一下上面就会出现大图
    javascript技巧大全
    div实现flash的遮照效果
    表格动态添加删除行
    云计算新模式将终结传统外包模式[转]
    源码过瑞星
    批处理创建、访问、重命名、删除畸形文件/文件夹
    //过360云查杀的代码
    NC反弹提权教程
  • 原文地址:https://www.cnblogs.com/Alan-Luo/p/10391789.html
Copyright © 2011-2022 走看看