[WC2010]重建计划(长链剖分版)

本文介绍了一种基于长链剖分的算法实现方法,通过维护动态数组来优化子树间最长链的计算过程,利用线段树进行区间查询与更新,解决了复杂路径上的最值问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门

Description

1758.jpg

Solution

时隔多年,补上了这题的长链剖分写法

感觉比点分治要好写的多

我们假设\(pos\)是当前点的\(dfn\),它距离所在链的底端的边的数量是\(len\),距离是\(siz\)

那么我们要求得\(g[pos...pos+len]\)

其中\(g[pos+i]+siz\)表示的是当前点往下长度为\(i\)的最长链的大小

初始情况下,\(g[pos]=-siz[pos]\)

为什么要这么写呢?

因为转移重儿子的时候,我们直接把数组右移了一位,这样子定义使得原先的值仍然有意义

考虑如何转移?

对于一个轻儿子,\(dfn\)\(pv\)

那么\(当前点,轻儿子g[pos+j+1]\leftarrow siz[pv]+g[pv+j]+w(当前点,轻儿子)-siz\)

考虑如何更新答案

对于\(lca\)为当前点的链

  1. 首先计算一个端点就是当前点的:\((g[pos+i])_{min}+siz\)

  2. 然后是两个端点分别处于不同子树的

    枚举一个轻儿子子树内的链长:\(当前点,轻儿子(g[pos+i])_{min}+siz+(siz[pv]+g[pv+j])+(w(当前点,轻儿子))\)

求min的部分用线段树优化


Code 

#include<bits/stdc++.h>
#define ll long long
#define reg register
#define ri reg int i
using namespace std;
inline int read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    return x*f;
}
const int MN=1e5+5;
const double eps=1e-4,inf=0x3f3f3f3f;
double siz[MN],g[MN],ans,mid;
struct edge{int to,w,nex;}e[MN<<1];int hr[MN],en;
inline void ins(int x,int y,int w)
{
    e[++en]=(edge){y,w,hr[x]};hr[x]=en;
    e[++en]=(edge){x,w,hr[y]};hr[y]=en;
}
int dfn[MN],len[MN],mx[MN],w[MN],ind,n,L,R;
struct SegmentTree
{
    #define ls (x<<1)
    #define rs (x<<1|1)
    #define Mid ((l+r)>>1)
    double t[MN<<2];
    inline void clear(){for(ri=0;i<(MN<<2);++i)t[i]=-inf;}
    void Modify(int x,int l,int r,int a,double val)
    {
        if(l==r) return(void)(t[x]=max(t[x],val));
        if(a<=Mid) Modify(ls,l,Mid,a,val);
        else Modify(rs,Mid+1,r,a,val);
        t[x]=max(t[ls],t[rs]);
    }
    double Query(int x,int l,int r,int a,int b)
    {
        if(l==a&&r==b) return t[x];if(a>b)return -inf;
        if(b<=Mid) return Query(ls,l,Mid,a,b);
        if(a>Mid) return Query(rs,Mid+1,r,a,b);
        return max(Query(ls,l,Mid,a,Mid),Query(rs,Mid+1,r,Mid+1,b));
    }
}T;
void dfs(int x,int f=0)
{
    for(ri=hr[x];i;i=e[i].nex)if(e[i].to^f)
    {
        dfs(e[i].to,x);
        if(len[e[i].to]>=len[mx[x]]) mx[x]=e[i].to,w[x]=e[i].w;
        if(len[e[i].to]+1>len[x]) len[x]=len[e[i].to]+1;
    }
}
void solve(int x,int f=0)
{
    if(!dfn[x]) dfn[x]=++ind;
    reg int i,j,pos=dfn[x];
    if(mx[x]) solve(mx[x],x),siz[pos]=siz[pos+1]+w[x]-mid;
    T.Modify(1,1,n,pos,g[pos]=-siz[pos]);
    if(L<=len[x])
    {
        double tmp=T.Query(1,1,n,pos+L,pos+min(len[x],R));
        ans=max(ans,tmp+siz[pos]);
    }   
    for(i=hr[x];i;i=e[i].nex)if(e[i].to!=f&&e[i].to!=mx[x])
    {
        solve(e[i].to,x);reg int pv=dfn[e[i].to];
        for(j=0;j<=len[e[i].to];++j)
        {
            double tmp=T.Query(1,1,n,pos+max(0,L-j-1),pos+min(len[x],R-j-1));
            ans=max(ans,tmp+siz[pv]+siz[pos]+g[pv+j]+e[i].w-mid);
        }
        for(j=0;j<=len[e[i].to];++j)
        {
            double tmp=siz[pv]+g[pv+j]+e[i].w-mid-siz[pos];
            if(tmp>g[pos+j+1]) T.Modify(1,1,n,pos+j+1,g[pos+j+1]=tmp);
        }
    }
}
bool check(){T.clear();ans=-inf;solve(1);return ans>=eps;}
int main()
{
    n=read();L=read();R=read();
    reg int i,x,y;
    for(i=1;i<n;++i) x=read(),y=read(),ins(x,y,read());
    dfs(1);double l=0.,r=1e6;
    for(i=1;i<=40;++i)
    {
        if(l+eps>=r) break;
        mid=(l+r)/2.;
        if(check()) l=mid;else r=mid;
    }
    printf("%.3lf",l);
    return 0;
}



Blog来自PaperCloud,未经允许,请勿转载,TKS!

转载于:https://www.cnblogs.com/PaperCloud/p/10662441.html

CH341A编程器是一款广泛应用的通用编程设备,尤其在电子工程和嵌入式系统开发领域中,它被用来烧录各种类型的微控制器、存储器和其他IC芯片。这款编程器的最新本为1.3,它的一个显著特点是增加了对25Q256等32M芯片的支持。 25Q256是一种串行EEPROM(电可擦可编程只读存储器)芯片,通常用于存储程序代码、配置数据或其他非易失性信息。32M在这里指的是存储容量,即该芯片可以存储32兆位(Mbit)的数据,换算成字节数就是4MB。这种大容量的存储器在许多嵌入式系统中都有应用,例如汽车电子、工业控制、消费电子设备等。 CH341A编程器的1.3更新,意味着它可以与更多的芯片型号兼容,特别是针对32M容量的芯片进行了优化,提高了编程效率和稳定性。26系列芯片通常指的是Microchip公司的25系列SPI(串行外围接口)EEPROM产品线,这些芯片广泛应用于各种需要小体积、低功耗和非易失性存储的应用场景。 全功能的CH341A编程器不仅支持25Q256,还支持其他大容量芯片,这意味着它具有广泛的兼容性,能够满足不同项目的需求。这包括但不限于微控制器、EPROM、EEPROM、闪存、逻辑门电路等多种类型芯片的编程。 使用CH341A编程器进行编程操作时,首先需要将设备通过USB连接到计算机,然后安装相应的驱动程序和编程软件。在本例中,压缩包中的"CH341A_1.30"很可能是编程软件的安装程序。安装后,用户可以通过软件界面选择需要编程的芯片类型,加载待烧录的固件或数据,然后执行编程操作。编程过程中需要注意的是,确保正确设置芯片的电压、时钟频率等参数,以防止损坏芯片。 CH341A编程器1.3是面向电子爱好者和专业工程师的一款实用工具,其强大的兼容性和易用性使其在众多编程器中脱颖而出。对于需要处理25Q256等32M芯片的项目,或者26系列芯片的编程工作,CH341A编程器是理想的选择。通过持续的软件更新和升级,它保持了与现代电子技术同步,确保用户能方便地对各种芯片进行编程和调试。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值