BZOJ 3545 / 洛谷 P4197 Peaks 解题报告

P4197 Peaks

题目描述

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

输入输出格式

输入格式:

第一行三个数\(N\)\(M\)\(Q\)。 第二行\(N\)个数,第\(i\)个数为\(h_i\)接下来\(M\)行,每行\(3\)个数\(a,b,c\),表示从\(a\)\(b\)有一条困难值为\(c\)的双向路径。 接下来\(Q\)行,每行三个数\(v,x,k\),一组询问。

输出格式:

对于每组询问,输出一个整数表示答案。

说明

数据范围

\(N \le 10^5\), \(0 \le M,Q \le 5\times 10^5\),\(h_i,c,x \le 10^9\)


恩,顺手学了一下重构树

觉得这篇洛谷日报讲的不错

说一下感受。

还是有点码量的,不太好调,写的时候认真一点,注意空间。


Code:

#include <cstdio>
#include <algorithm>
const int N=1e5+10;
const int M=5e5+10;
int n,m,q,F[N<<1],dfn[N<<1],low[N<<1],dfs_clock,ha[N<<1],f[N<<1][19],poi[N<<1];
int th[N],h[N];
struct node
{
    int u,v,w;
    bool friend operator <(node n1,node n2){return n1.w<n2.w;}
}e[M];
int Find(int x){return F[x]=F[x]==x?x:Find(F[x]);}
int Next[N<<1],to[N<<1],head[N<<1],cnt;
void add(int u,int v){to[++cnt]=v,Next[cnt]=head[u],head[u]=cnt;}
void dfs(int now)
{
    for(int i=1;f[now][i-1];i++) f[now][i]=f[f[now][i-1]][i-1];
    dfn[now]=++dfs_clock,ha[dfs_clock]=now;
    for(int i=head[now];i;i=Next[i])
        dfs(to[i]);
    low[now]=dfs_clock;
}
int sum[N*30],ch[N*30][2],root[N<<1],tot;
#define ls ch[now][0]
#define rs ch[now][1]
#define ols ch[las][0]
#define ors ch[las][1]
int rebuild(int las,int l,int r,int pos)
{
    int now=++tot,mid=l+r>>1;
    if(l==r) return sum[now]=sum[las]+1,now;
    if(pos<=mid)
    {
        ls=rebuild(ols,l,mid,pos);
        rs=ors;
    }
    else
    {
        ls=ols;
        rs=rebuild(ors,mid+1,r,pos);
    }
    return sum[now]=sum[ls]+sum[rs],now;
}
int query(int now,int las,int l,int r,int k)
{
    if(k>sum[now]-sum[las]) return 0;
    if(l==r) return l;
    int mid=l+r>>1;
    if(sum[rs]-sum[ors]>=k)
        return query(rs,ors,mid+1,r,k);
    else
        return query(ls,ols,l,mid,k-sum[rs]+sum[ors]);
}
int find(int v,int x)//v不大于x的点
{
    for(int i=18;~i;i--)
        if(poi[f[v][i]]<=x)
            v=f[v][i];
    return v;
}
int main()
{
    scanf("%d%d%d",&n,&m,&q);
    int n_=n;
    for(int i=1;i<=n;i++) scanf("%d",h+i),th[i]=h[i];
    for(int i=1;i<=m;i++)
        scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].w);
    std::sort(e+1,e+1+m);
    std::sort(th+1,th+1+n);
    int m_=std::unique(th+1,th+1+n)-th-1;
    for(int i=1;i<=n;i++) h[i]=std::lower_bound(th+1,th+1+m_,h[i])-th;
    th[0]=-1,poi[0]=0x7fffffff;
    for(int i=1;i<=n*2;i++) F[i]=i;
    for(int i=1;i<=m;i++)
    {
        int u=e[i].u,v=e[i].v,w=e[i].w;
        int rt1=Find(u),rt2=Find(v);
        if(rt1==rt2) continue;
        F[rt1]=F[rt2]=f[rt1][0]=f[rt2][0]=++n;
        add(n,rt1),add(n,rt2);
        poi[n]=w;
    }
    dfs(n);
    for(int i=1;i<=dfs_clock;i++)
    {
        if(ha[i]<=n_)
            root[i]=rebuild(root[i-1],1,m_,h[ha[i]]);
        else
            root[i]=root[i-1];
    }
    for(int anc,v,x,k,i=1;i<=q;i++)
    {
        scanf("%d%d%d",&v,&x,&k);
        anc=find(v,x);
        printf("%d\n",th[query(root[low[anc]],root[dfn[anc]-1],1,m_,k)]);
    }
    return 0;
}

2018.10.16

转载于:https://www.cnblogs.com/butterflydew/p/9798549.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SQLAlchemy 是一个 SQL 工具包和对象关系映射(ORM)库,用于 Python 编程语言。它提供了一个高级的 SQL 工具和对象关系映射工具,允许开发者以 Python 类和对象的形式操作数据库,而无需编写大量的 SQL 语句。SQLAlchemy 建立在 DBAPI 之上,支持多种数据库后端,如 SQLite, MySQL, PostgreSQL 等。 SQLAlchemy 的核心功能: 对象关系映射(ORM): SQLAlchemy 允许开发者使用 Python 类来表示数据库表,使用类的实例表示表中的行。 开发者可以定义类之间的关系(如一对多、多对多),SQLAlchemy 会自动处理这些关系在数据库中的映射。 通过 ORM,开发者可以像操作 Python 对象一样操作数据库,这大大简化了数据库操作的复杂性。 表达式语言: SQLAlchemy 提供了一个丰富的 SQL 表达式语言,允许开发者以 Python 表达式的方式编写复杂的 SQL 查询。 表达式语言提供了对 SQL 语句的灵活控制,同时保持了代码的可读性和可维护性。 数据库引擎和连接池: SQLAlchemy 支持多种数据库后端,并且为每种后端提供了对应的数据库引擎。 它还提供了连接池管理功能,以优化数据库连接的创建、使用和释放。 会话管理: SQLAlchemy 使用会话(Session)来管理对象的持久化状态。 会话提供了一个工作单元(unit of work)和身份映射(identity map)的概念,使得对象的状态管理和查询更加高效。 事件系统: SQLAlchemy 提供了一个事件系统,允许开发者在 ORM 的各个生命周期阶段插入自定义的钩子函数。 这使得开发者可以在对象加载、修改、删除等操作时执行额外的逻辑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值