P4381 [IOI2008]Island(基环树+单调队列优化dp)

P4381 [IOI2008]Island

题意:求图中所有基环树的直径和

我们对每棵基环树分别计算答案。

首先我们先bfs找环(dfs易爆栈)

蓝后我们处理直径

直径不在环上,就在环上某点的子树上

我们对于环上每个点的子树,跑一边dp求直径即可,顺带处理子树的最深深度(环上点到子树某个叶节点的最长距离)$dis[x]$

在dfs求直径时顺带求直径的最大值(可能是整棵基环树的直径)

蓝后我们在环上跑一遍dp。

我们先破环成链(就是把长度为$n$的环转换成长$2n+1$的链)

偷个图

 

我们记链上前$i$个点之间边的总长(前缀和)$sum[i]$

枚举$j(1<=j<i,i-j<n)$,得

$ans=max(ans,dis[i]+sum[i]-sum[j]+dis[j])$,表示子树$i$的直径$+$子树$j$的直径+$i,j$在环上之间的距离

我们分离一下上面的式子:$(dis[i]+sum[i])+(dis[j]-sum[j])$

这不是可以单调队列维护

于是再搞个单调队列优化dp就完事辣

bzoj还是爆栈了TAT

#include<iostream>
#include<cstdio>
#include<cstring>
#define rint register int
using namespace std;
typedef long long ll;
inline ll Max(ll a,ll b){return a>b?a:b;}
void read(int &x){
    char c=getchar();x=0;
    while(c<'0'||c>'9') c=getchar();
    while('0'<=c&&c<='9') x=x*10+(c^48),c=getchar();
}
#define N 1000005
int n,ri[N],d[N],is[N],To[N],W[N],fa[N],len,L,R,h[N]; 
ll ans,re,sum[N],dis[N]; bool vis[N];
int cnt,hd[N],nxt[N<<1],ed[N],poi[N<<1],val[N<<1];
inline void adde(int x,int y,int v){
    nxt[ed[x]]=++cnt, hd[x]=hd[x]?hd[x]:cnt;
    ed[x]=cnt, poi[cnt]=y, val[cnt]=v;
}
void bfs(int x){//找环
    rint p; vis[x]=1;len=0;
    while(1){
        p=To[x];
        if(vis[p]){
            ri[++len]=p,d[len]=W[p],is[p]=1;
            for(;x!=p;x=fa[x])
                ri[++len]=x,d[len]=W[x],is[x]=1;
            break;
        }vis[p]=1;fa[p]=x;x=p;
    }
}
void dfs(int x,int Fa){//dfs求子树直径
    vis[x]=1;
    for(int i=hd[x];i;i=nxt[i]){
        int to=poi[i];
        if(is[to]||to==Fa) continue;
        dfs(to,x); re=Max(re,dis[x]+dis[to]+(ll)val[i]);
        dis[x]=Max(dis[x],dis[to]+val[i]);
    }
}
inline int Id(int x){return (x-1)%len+1;}
inline ll F(int x){return dis[ri[Id(x)]]-sum[x];}
void solve(){//单调队列优化,环上dp
    L=1;R=0;
    for(rint i=1;i<=len*2;++i){
        sum[i]=sum[i-1]+d[Id(i)];
        while(L<=R&&i-h[L]>=len) ++L;
        if(L<=R) re=Max(re,F(h[L])+dis[ri[Id(i)]]+sum[i]);
        while(L<=R&&F(h[R])<=F(i)) --R;
        h[++R]=i;
    }
}
int main(){
    read(n);
    for(rint i=1;i<=n;++i){
        read(To[i]); read(W[i]);
        adde(i,To[i],W[i]); adde(To[i],i,W[i]);
    }
    for(rint i=1;i<=n;++i){
        if(vis[i]) continue;
        re=0; bfs(i);
        for(rint j=1;j<=len;++j) dfs(ri[j],0);
        solve(); ans+=re;//每棵树分别处理
    }printf("%lld",ans);
    return 0;
}

 

转载于:https://www.cnblogs.com/kafuuchino/p/10651547.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、付费专栏及课程。

余额充值