• 挺进


    挺进

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

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

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

    如何合并呢?

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

    具体细节见代码

    #include <iostream>
    #include <cmath>
    #include <cstdio>
    #include <algorithm>
    using namespace std;
    #define int long long
    #define ls (p<<1)
    #define rs (p<<1|1)
    #define mid ((l+r)>>1)
    // typedef long long int;
    const int N=200010;
    inline int read() {
    	int x=0;char ch=getchar();
    	while(!isdigit(ch)) ch=getchar();
    	while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    	return x;
    }
    
    int n;
    int hd[N],tot,to[N],nxt[N],w[N];
    inline void add(int x,int y,int z) {
    	to[++tot]=y;w[tot]=z;nxt[tot]=hd[x];hd[x]=tot;
    }
    
    int dis[N];
    int fa[N],dep[N],siz[N],son[N];
    void dfs_son(int x,int f) {
    	fa[x]=f;siz[x]=1;dep[x]=dep[f]+1;
    	for(int i=hd[x];i;i=nxt[i]) {
    		int y=to[i];
    		if(y==f) continue;
    		dis[y]=dis[x]+w[i];
    		dfs_son(y,x);
    		siz[x]+=siz[y];
    		if(siz[y]>siz[son[x]]) son[x]=y;
    	}
    }
    
    int dfnin[N],dfnout[N],rev[N],top[N],dfn_cnt;
    void dfs_chain(int x,int tp) {
    	top[x]=tp;
    	dfnin[x]=++dfn_cnt;rev[dfn_cnt]=x;
    	if(son[x]) dfs_chain(son[x],tp);
    	for(int i=hd[x];i;i=nxt[i]) {
    		int y=to[i];
    		if(dfnin[y]) continue;
    		dfs_chain(y,y);
    	}	
    	dfnout[x]=dfn_cnt;
    }
    
    inline int get_dia(int x,int y) {
    	if(!x||!y) return 0;
    	int sum=dis[x]+dis[y];
    	while(top[x]!=top[y]) {
    		if(dep[top[x]]<dep[top[y]]) swap(x,y);
    		x=fa[top[x]];
    	}
    	return sum-(dep[x]<dep[y]?dis[x]:dis[y])*2;
    }
    
    struct TREE{
    	int x,y;
    	int v;
    	TREE() {}
    	TREE(int x_,int y_,int v_) {x=x_;y=y_;v=v_;}
    }t[N<<1];
    TREE Max(TREE a,TREE b) {return a.v<b.v?b:a;}
    TREE get(int a,int b) {return TREE(a,b,get_dia(a,b));}
    TREE merge(TREE a,TREE b) {
    	return Max(Max(a,b),Max(Max(get(a.x,b.x),get(a.y,b.y)),Max(get(a.x,b.y),get(a.y,b.x))));
    }
    void build(int l,int r,int p) {
    	if(l==r) {
    		t[p]=TREE(rev[l],rev[l],0);
    		return;
    	}
    	build(l,mid,ls);
    	build(mid+1,r,rs);
    	t[p]=merge(t[ls],t[rs]);
    }
    TREE query(int l,int r,int L,int R,int p) {
    	if(L>R) return TREE(0,0,0);
    	if(L<=l&&r<=R) return t[p];
    	TREE res=TREE(0,0,-1);
    	if(L<=mid) res=query(l,mid,L,R,ls);
    	if(R>mid) res=merge(res,query(mid+1,r,L,R,rs));
    	return res;
    }
    signed main() {
    	n=read();
    	for(int i=1,x,y,z;i<n;i++) {
    		x=read();y=read();z=read();
    		add(x,y,z);
    		add(y,x,z);
    	}
    	dfs_son(1,0);
    	dfs_chain(1,1);
    	build(1,n,1);
    	int ans=0;
    	for(int i=1;i<n;i++) {
    		TREE a=query(1,n,dfnin[i],dfnout[i],1);
    		TREE b=query(1,n,1,dfnin[i]-1,1);
    		TREE c=query(1,n,dfnout[i]+1,n,1);
    		ans=max(ans,a.v+merge(b,c).v);
    	}
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    SQL Server的AlwaysOn错误19456和41158
    kvm上的Linux虚拟机使用virtio磁盘
    利用HAProxy代理SQL Server的AlwaysOn辅助副本
    KVM安装部署
    ola.hallengren的SQL Server维护脚本
    在单链表的第i个位置后插入一个节点(阿里+腾讯等面试题总结)
    怎么发现RAC环境中&#39;library cache pin&#39;等待事件的堵塞者(Blocker)?
    php unserialize 返回false的解决方法
    千万别让这些举动断送了你的职业前程-好文共分享
    Android开发:仿美团下拉列表菜单,帮助类,复用简单
  • 原文地址:https://www.cnblogs.com/ke-xin/p/13526065.html
Copyright © 2020-2023  润新知