• 联赛模拟18_联盟(线段树维护树的直径)





    没有用(O(n))的做法,是(O(nlogn))的线段树维护直径

    将树的节点按(dfs)序建线段树维护联通块的直径

    枚举每一条边,查看删掉它之后,剩余的两个联通块合并后的直径 所能取到的 最小的最大值

    即 最小的 (len)=(max) ((l1,l2,frac{l1+1}{2}) + (frac{l2+1}{2}) +1}

    (l1和l2) 是两个联通块的直径。

    记录(len)的最小值及其个数,以及此时的要删的边的编号。

    对于找端点,选一条要删的边,输出其端点,然后分别(dfs)找到两个联通块直径的中点输出即可

    Code
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <cmath>
    #include <cctype>
    using namespace std;
    char buf[1<<20],*p1,*p2;
    #define L (rt*2)
    #define R (rt*2+1)
    #define rint register int
    #define gc() (p1==p2?(p2=buf+fread(p1=buf,1,1<<20,stdin),p1==p2?EOF:*p1++):*p1++)
    #define read() ({
    	rint x=0;register bool f=0;register char ch=gc();
    	while(!isdigit(ch)) f|=ch=='-',ch=gc();
    	while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch&15),ch=gc();
    	f?-x:x;
    })
    const int maxn=3e5+5;
    int n;
    int cnt;
    int Time;
    int head[maxn];
    int dfn[maxn],ref[maxn];
    int dep[maxn],fa[maxn],son[maxn],siz[maxn],top[maxn];
    int Min=0x3f3f3f3f;
    int mx[maxn][2];
    int jilu[maxn];
    int G,max_part;
    int no_vis;
    
    struct Seg{ int x,y; }t[maxn*4];
    struct Edge{ int from,to,next; }e[maxn*2],ed[maxn];
    
    void Aedge(int x,int y){
    	e[++cnt].to=y;
    	e[cnt].next=head[x];
    	head[x]=cnt;
    }
    void dfs1(int x,int prt){
    	siz[x]=1,fa[x]=prt,dep[x]=dep[prt]+1;
    	for(int i=head[x];i;i=e[i].next){
    		const rint y=e[i].to;
    		if(y==prt) continue;
    		dfs1(y,x);
    		siz[x]+=siz[y];
    		if(!son[x]||siz[son[x]]<siz[y]) son[x]=y;
    	}
    }
    void dfs2(int x,int tp){
    	top[x]=tp,dfn[x]=++Time,ref[Time]=x;
    	if(son[x]) dfs2(son[x],tp);
    	for(int i=head[x];i;i=e[i].next){
    		const rint y=e[i].to;
    		if(y!=son[x]&&y!=fa[x]) dfs2(y,y);
    	}
    }
    int lca(int x,int y){
    	while(top[x]!=top[y]){
    		if(dep[top[x]]<dep[top[y]]) swap(x,y);
    		x=fa[top[x]];
    	}
    	return dep[x]<dep[y]?x:y;
    }
    int cal(int x,int y){
    	return dep[x]+dep[y]-dep[lca(x,y)]*2;
    }
    
    int res[5],xx,yy,max_len;
    Seg up(Seg A,Seg B){
    	Seg ans;
    	max_len=-1;
    	res[1]=A.x,res[2]=A.y,res[3]=B.x,res[4]=B.y;
    	for(int i=1;i<=4;++i){
    		for(int j=i+1;j<=4;++j){
    			const rint dis=cal(res[i],res[j]);
    			if(dis>max_len){
    				max_len=dis;
    				xx=res[i];
    				yy=res[j];
    			}
    		}
    	}
    	ans=(Seg){xx,yy};
    	return ans;
    }
    void build(int rt,int l,int r){
    	if(l==r) return t[rt].x=t[rt].y=ref[l],void();
    	const int mid=(l+r)/2;
    	build(L,l,mid),build(R,mid+1,r);
    	t[rt]=up(t[L],t[R]);
    }
    Seg find(int rt,int l,int r,int x,int y){
    	if(x==l&&r==y) return t[rt];
    	int mid=(l+r)/2;
    	if(y<=mid) return find(L,l,mid,x,y);
    	if(x >mid) return find(R,mid+1,r,x,y);
    	return up(find(L,l,mid,x,mid),find(R,mid+1,r,mid+1,y));
    }
    
    void dfs(int x,int prt){
    	mx[x][0]=0,mx[x][1]=0;
    	for(int i=head[x];i;i=e[i].next){
    		const int y=e[i].to;
    		if(y==prt||y==no_vis) continue;
    		dfs(y,x);
    		if(mx[y][0]+1>mx[x][0]) mx[x][1]=mx[x][0],mx[x][0]=mx[y][0]+1;
    		else if(mx[y][0]+1>mx[x][1]) mx[x][1]=mx[y][0]+1;
    	}
    }
    void find_G(int x,int prt,int dep){
    	if(!G||max(mx[x][0],dep)<max_part) max_part=max(mx[x][0],dep),G=x;
    	for(int i=head[x];i;i=e[i].next){
    		int y=e[i].to;
    		if(y==prt||y==no_vis) continue;
    		int tmp;
    		if(mx[x][0]==mx[y][0]+1) find_G(y,x,max(dep+1,mx[x][1]+1));
    		else find_G(y,x,max(dep+1,mx[x][0]+1));
    	}
    }
    int main(){
    	freopen("league.in","r",stdin);
    	freopen("league.out","w",stdout);
    	n=read();
    	for(int i=1;i<n;++i){
    		Aedge(ed[i].from=read(),ed[i].to=read());
    		Aedge(ed[i].to,ed[i].from);
    	}
    	dfs1(1,0);
    	dfs2(1,1);
    	build(1,1,n);
    	for(int i=1;i<n;++i){
    		int x=ed[i].from,y=ed[i].to;
    		if(dep[x]>dep[y]) swap(x,y);
    
    		Seg a2;
    		if(dfn[y]+siz[y]<=Time) a2=up(find(1,1,n,1,dfn[y]-1),find(1,1,n,dfn[y]+siz[y],Time));
    		else a2=find(1,1,n,1,dfn[y]-1);
    		int len2=cal(a2.x,a2.y);
    		if(len2>Min) continue;
    	
    		Seg a1=find(1,1,n,dfn[y],dfn[y]+siz[y]-1);
    		int len1=cal(a1.x,a1.y);
    		if(len1>Min) continue;
    
    		int d=max(max(len1,len2),(len1+1)/2+(len2+1)/2+1);
    		if(d<Min){
    			Min=d;
    			jilu[jilu[0]=1]=i;
    		}
    		else if(d==Min) jilu[++jilu[0]]=i;
    	}
    	printf("%d
    %d ",Min,jilu[0]);
    	for(int i=1;i<=jilu[0];++i) printf("%d ",jilu[i]);
    	printf("
    ");
    
    	int x=ed[jilu[1]].from,y=ed[jilu[1]].to;
    	printf("%d %d ",x,y);
    	no_vis=y;
    	max_part=0x3f3f3f3f;
    	dfs(x,0),find_G(x,0,0);
    	printf("%d ",G);
    
    	no_vis=x;
    	max_part=0x3f3f3f3f;
    	dfs(y,0),find_G(y,0,0);
    	printf("%d
    ",G);
    	
    	return 0;
    }
    
  • 相关阅读:
    [转]javaweb学习总结(二十二)——基于Servlet+JSP+JavaBean开发模式的用户登录注册
    [转]javaweb学习总结(二十一)——JavaWeb的两种开发模式
    [转]javaweb学习总结(二十)——JavaBean总结
    [转]javaweb学习总结(十九)——JSP标签
    [转]javaweb学习总结(十八)——JSP属性范围
    [转]JavaWeb学习总结(十七)——JSP中的九个内置对象
    [转]javaweb学习总结(十六)——JSP指令
    [转]javaweb学习总结(十五)——JSP基础语法
    TypeScript
    TypeScript
  • 原文地址:https://www.cnblogs.com/Lour688/p/13831074.html
Copyright © 2020-2023  润新知