zoukankan      html  css  js  c++  java
  • Jzoj4727 挺进

    题意:给你一颗树,要求断掉一条边,使得剩下两个联通快的直径之和最大

    一看就是树形DP嘛,c1表示最长边c2次长,f表示父亲部分的最长路

    上面做法不讲,我们讲一种比较新奇的方法

    假设我们枚举断哪一条边,在lgn时间内求出两个联通快的直径不就行了嘛

    怎么做呢,我们发现,可以用树的dfs序来维护,我们用一个线段树维护一个区间内的直径的端点和长度

    额,如何合并?

    我们假设两块的直径端点分别为x1,y1,x2,y2,那么结果就是在这四个点中取2个的所有方案的最大值(证明显然)

    但是这道题这样做复杂度较高(n lg^2 n),如果求lca能用rmq就可以将为(n lg n),然而我比较懒用了树剖,而且jz跑的快就过了

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    #define N 100010
    #define LL long long
    using namespace std;
    struct Edge{ int v,c,nt; } G[N<<1];
    struct Node{ int x,y; LL v; } s[N<<2];
    int h[N],sz[N],son[N],top[N],d[N],f[N];
    int n,cnt=0,clk=0,nl[N],nr[N],c[N]; LL dis[N];
    inline void adj(int x,int y,int c){
    	G[++cnt]=(Edge){y,c,h[x]}; h[x]=cnt;
    }
    void dfs(int x,int p){
    	d[x]=d[p]+1; f[x]=p; sz[x]=1;
    	for(int v,i=h[x];i;i=G[i].nt)
    		if((v=G[i].v)!=p){
    			dis[v]=dis[x]+G[i].c;
    			dfs(v,x); sz[x]+=sz[v];
    			if(sz[v]>sz[son[x]]) son[x]=v;
    		}
    }
    void dgs(int x,int p){
    	nl[x]=++clk; c[clk]=x; top[x]=p;
    	if(son[x]) dgs(son[x],p);
    	for(int v,i=h[x];i;i=G[i].nt)
    		if((v=G[i].v)!=f[x] && v!=son[x]) dgs(v,v);
    	nr[x]=clk;
    }
    inline LL gLca(int x,int y){
    	if(!x || !y) return 0;
    	LL S=dis[x]+dis[y];
    	for(;top[x]!=top[y];y=f[top[y]])
    		if(d[top[x]]>d[top[y]]) swap(x,y);
    	return S-((d[x]<d[y]?dis[x]:dis[y])<<1);
    }
    inline Node gNod(int x,int y){ return (Node){x,y,gLca(x,y)}; }
    inline Node max(Node a,Node b){ return a.v<b.v?b:a; }
    inline Node merge(Node a,Node b){
    	return max(max(a,b),max(max(gNod(a.x,b.x),gNod(a.x,b.y)),max(gNod(a.y,b.x),gNod(a.y,b.y))));
    }
    void build(int l,int r,int x){
    	if(l==r){ s[x]=(Node){c[l],c[l],0}; return; }
    	int m=l+r>>1;
    	build(l,m,x<<1);
    	build(m+1,r,x<<1|1);
    	s[x]=merge(s[x<<1],s[x<<1|1]);
    }
    Node query(int l,int r,int x,int L,int R){
    	if(L>R) return (Node){0,0,0};
    	if(L<=l && r<=R) return s[x];
    	int m=l+r>>1; Node A=(Node){0,0,-1};
    	if(L<=m) A=query(l,m,x<<1,L,R);
    	if(m<R) A=merge(A,query(m+1,r,x<<1|1,L,R));
    	return A;
    }
    int main(){
    	scanf("%d",&n);
    	for(int x,y,c,i=1;i<n;++i){
    		scanf("%d%d%d",&x,&y,&c);
    		adj(x,y,c); adj(y,x,c);
    	}
    	dfs(1,0); dgs(1,1); build(1,n,1);
    	LL A=0;
    	for(int i=2;i<=n;++i){
    		Node a,b,c;
    		a=query(1,n,1,nl[i],nr[i]);
    		b=query(1,n,1,1,nl[i]-1);
    		c=query(1,n,1,nr[i]+1,n);
    		A=max(A,a.v+merge(b,c).v);
    	}
    	printf("%lld
    ",A);
    }

  • 相关阅读:
    webjars管理静态资源
    SpringCloud踩坑日记
    ELK日志搜索平台搭建
    新硬盘挂载到目录后目录原先数据消失解决办法
    nginx安装缺少依赖记录
    SpringCloud踩坑日记
    .bashrc配错刷新导致linux基础命令不能用修复
    nginx超时时间配置
    nginx日志切分shell脚本
    2019.10.10 实习日记
  • 原文地址:https://www.cnblogs.com/Extended-Ash/p/7774358.html
Copyright © 2011-2022 走看看