zoukankan      html  css  js  c++  java
  • 题解 [NOIP2015]运输计划

    题解 [NOIP2015]运输计划

    题面

    解析

    首先肯定是要求出每条路径的长度.

    这个用节点到根的前缀和就行了(一开始脑抽写了个线段树...)

    然后有一个显然的类似贪心的想法,

    就是你改造的边肯定在最长的路径上,

    (不然没有*用)

    那么考虑枚举最长的路径上的边,计算改造它的答案,

    对于边(x),路径可以分为两类:经过它的和不经过它的.

    在它被改造后,经过它的路径就都减少了它的长度,

    于是最长的就还是这条最长的路径,

    而没经过它的就没有受到影响,取最长的路径,

    因此删掉(x)的答案就是上面两种情况的(max),

    但关键就是怎么求第二种情况:没经过(x)的最长的路径.

    枚举边再一个个求似乎不可行,

    我们可以考虑枚举路径计算它对边的贡献,

    显然没在这条路径上的边都可以被这条路径更新,

    于是考虑树剖,

    这样一条路径就被划分成了若干个区间,

    而区间的补集就是它要更新的边,

    把边的答案对应到深度较大的点上,用线段树维护最大值即可.

    code(代码挺长但仔细康康应该能懂):

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define fot for
    #define ls(a) a<<1
    #define rs(a) a<<1|1
    #define fre(x) freopen(x".in","r",stdin),freopen(x".out","w",stdout)
    using namespace std;
    
    inline int read(){
    	int sum=0,f=1;char ch=getchar();
    	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    	return f*sum;
    }
    
    const int N=3000005;
    struct ques{int s,t,w;}q[N];
    struct edge{int to,next,w;}e[N<<1];
    struct tree{int l,r,sum,maxn,tag;}t[N<<1];
    struct qujian{int l,r;}sta[N];
    struct node{int size,son,id,fa,dep,top,val;}a[N];
    int n,m,tot,pla[N],ans;
    int head[N],cnt,s[N];
    
    inline void add(int x,int y,int w){
    	e[++cnt]=(edge){head[x],y,w};head[x]=cnt;
    }
    
    inline void dfs1(int x,int fa){
    	a[x].size=1;a[x].fa=fa;
    	a[x].dep=a[fa].dep+1;
    	for(int i=head[x];i;i=e[i].to){
    		int k=e[i].next;		
    		if(k==fa) continue;
    		s[k]=s[x]+e[i].w;
    		dfs1(k,x);a[k].val=e[i].w;
    		a[x].size+=a[k].size;
    		if(a[k].size>a[a[x].son].size) a[x].son=k;
    	}
    }
    
    inline void dfs2(int x,int top){
    	a[x].top=top;a[x].id=++tot;
    	pla[tot]=x;
    	if(a[x].son) dfs2(a[x].son,top);
    	for(int i=head[x];i;i=e[i].to){
    		int k=e[i].next;
    		if(k==a[x].fa||k==a[x].son) continue;
    		dfs2(k,k);
    	}
    }
    
    inline void build(int p,int l,int r){
    	t[p].l=l;t[p].r=r;
    	if(l==r) {t[p].sum=a[pla[l]].val;return ;}
    	int mid=(l+r)>>1;
    	build(ls(p),l,mid);build(rs(p),mid+1,r);
    }
    
    inline int lca(int x,int y){
    	while(a[x].top!=a[y].top){
    		if(a[a[x].top].dep<a[a[y].top].dep) swap(x,y);
    		x=a[a[x].top].fa;
    	}
    	if(a[x].dep>a[y].dep) swap(x,y);
    	return x;
    }
    
    inline int dis(int x,int y){
    	return s[x]+s[y]-2*s[lca(x,y)];
    }
    
    inline bool cmp(ques a,ques b){return a.w>b.w;}
    
    inline void Pushup(int p){
    	t[p].maxn=max(t[ls(p)].maxn,t[rs(p)].maxn);
    }
    
    inline void Pushdown(int p){
    	int ret=t[p].tag;
    	t[ls(p)].tag=max(t[ls(p)].tag,ret);
    	t[rs(p)].tag=max(t[rs(p)].tag,ret);
    	t[ls(p)].maxn=max(t[ls(p)].maxn,ret);
    	t[rs(p)].maxn=max(t[rs(p)].maxn,ret);
    }
    
    inline void change(int p,int l,int r,int w){
    	if(l>r||!l||!r) return ;
    	if(t[p].l>=l&&t[p].r<=r){
    		t[p].maxn=max(t[p].maxn,w);
    		t[p].tag=max(t[p].tag,w);
    		return ;
    	}
    	Pushdown(p);
    	int mid=(t[p].l+t[p].r)>>1;
    	if(l<=mid) change(ls(p),l,r,w);
    	if(r>mid) change(rs(p),l,r,w);
    	Pushup(p);
    }
    
    inline bool cmp1(qujian a,qujian b){return a.l<b.l;}
    
    inline void find(int x,int y,int w){
    	int top=0;
    	while(a[x].top!=a[y].top){
    		if(a[a[x].top].dep<a[a[y].top].dep) swap(x,y);
    		sta[++top]=(qujian){a[a[x].top].id,a[x].id};
    		x=a[a[x].top].fa;
    	}
    	if(a[x].dep>a[y].dep) swap(x,y);
    	sta[++top]=(qujian){a[x].id+1,a[y].id};
    	int L=1,R;
    	sort(sta+1,sta+top+1,cmp1);
    	for(int i=1;i<=top;i++){
    		R=sta[i].l-1;
    		change(1,L,R,w);
    		L=sta[i].r+1;
    	}
    	change(1,L,n,w);
    }
    
    inline int search(int p,int x){
    	if(t[p].l==t[p].r) return t[p].maxn;
    	Pushdown(p);
    	int mid=(t[p].l+t[p].r)>>1;
    	if(x<=mid) return search(ls(p),x);
    	else return search(rs(p),x);
    }
    
    inline void solve(int x,int y){
    	int pp=lca(x,y);
    	while(x!=pp){
    		ans=min(ans,max(q[1].w-a[x].val,search(1,a[x].id)));
    		x=a[x].fa;
    	}
    	while(y!=pp){
    		ans=min(ans,max(q[1].w-a[y].val,search(1,a[y].id)));
    		y=a[y].fa;		
    	}
    }
    
    signed main(){
    	n=read();m=read();	
    	for(int i=1;i<n;i++){
    		int x=read(),y=read(),w=read();
    		add(x,y,w);add(y,x,w);
    	}
    	for(int i=1;i<=m;i++){
    		q[i].s=read(),q[i].t=read();
    	}
    	dfs1(1,0);dfs2(1,1);
    	build(1,1,n);
    	for(int i=1;i<=m;i++){
    		q[i].w=dis(q[i].s,q[i].t);
    	}
    	for(int i=1;i<=m;i++) find(q[i].s,q[i].t,q[i].w);
    	sort(q+1,q+m+1,cmp);
    	ans=q[1].w;
    	fot(int i=1;i<=m;i++)
    		if(q[i].w==q[1].w) solve(q[i].s,q[i].t);
    		else break;
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    C# Split() 去除 分组
    C#获取当前路径的7种方法
    给 C# 开发者的代码审查清单
    【知乎】一句话答案收录集,一句足矣
    C# string和byte[]的转换
    WCF 有零个操作;协定必须至少有一个操作
    WPF中动态改变控件显示位置
    转 将iPhone和Android手机屏幕投影仪投影显示
    转 MySQL数据库监控软件lepus使用问题以及解决办法
    转 Shell中的IFS解惑
  • 原文地址:https://www.cnblogs.com/zsq259/p/11828299.html
Copyright © 2011-2022 走看看