附加点AC,其他全WA
查看原帖
附加点AC,其他全WA
637073
wujingfey楼主2024/10/17 22:05

问题所在:提交到弱化版 P1099 能通过,n<=3000n<=3000 以内与 std 对拍 3000+ 组数据全过。但交上去 0pts0pts

思路:找到树的直径后二分答案 xx,然后两次遍历直径,检验能不能找到路径满足 xx 限制且距离小于等于 ss

#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5;
int n,s,dis[N],len[N],col[N],S,T,l,r;
int st[N],tp,f=1;
vector<pair<int,int> > e[N]; 
void dfs(int u,int fa){
	if(dis[u]>dis[S]) S=u;
	for(auto p:e[u]){
		int v=p.first, w=p.second;
		if(v==fa) continue;
		dis[v]=dis[u]+w;
		dfs(v,u);
	}
}
void get(int u,int fa){
	st[++tp]=u;
	if(u==T){
		f=0;
		return;
	}
	for(auto p:e[u]){
		int v=p.first;
		if(v==fa) continue;
		get(v,u);
		if(f==0) return;
	}
	tp--;
}
void dfs2(int u,int fa){
	for(auto p:e[u]){
		int v=p.first, w=p.second;
		if(v==fa) continue;
		dfs2(v,u);
		len[u]=len[v]+w;
	}
}
bool chk(int x){ 
	int x1=0,x2=0;
	for(int i=1;i<=tp;i++){
		for(auto p:e[st[i]]){
			int v=p.first, w=p.second;
			if(len[v]+w>x && col[v]==0) return false;
		}
		if(abs(dis[S]-dis[st[i]])>x){
			if(i==1) x1=0;
			else x1=abs(dis[S]-dis[st[i-1]]);
			break;
		}
	}
	for(int i=tp;i>=0;i--){
		for(auto p:e[st[i]]){
			int v=p.first, w=p.second;
			if(len[v]+w>x && col[v]==0) return false;
		}
		if(abs(dis[T]-dis[st[i]])>x){
			if(i==tp) x2=0;
			else x2=abs(dis[T]-dis[st[i+1]]);
			break;
		}
	}
	if(dis[S]-x1-x2>s) return false;
	return true;
}
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);
	cin>>n>>s;
	for(int i=1;i<n;i++){
		int x,y,z; cin>>x>>y>>z;
		e[x].push_back({y,z});
		e[y].push_back({x,z});
	}
	memset(dis,0,sizeof dis);
	dfs(1,0);
	memset(dis,0,sizeof dis);
	T=S,S=0; dfs(T,0);
	get(S,0);//找出直径路径 
	for(int i=1;i<=tp;i++){
		col[st[i]]=1;//给直径上的点打上标记 
	}
	dfs2(S,0);//以S为根求每个点到直径的距离最大值 
	l=0, r=dis[S];
	while(l<r){//二分答案 
		int mid=(l+r)>>1;
		if(chk(mid)) r=mid;
		else l=mid+1;
	}
	cout<<l<<endl;
	return 0;
}
2024/10/17 22:05
加载中...