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


    传送门

    Description

    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!

  • 相关阅读:
    mvn
    MySQL 数据类型
    Request获取客户端IP
    struts1
    tomcat8.5 Host-Manager配置访问的方法
    struts2框架
    windows注册表
    windows常用命令
    浏览器内核
    创建分区swap分区
  • 原文地址:https://www.cnblogs.com/PaperCloud/p/10662441.html
Copyright © 2020-2023  润新知