USACO 2009 January Gold 安全路径

探讨如何利用最短路径树和树剖技术解决特定路径寻找问题,通过避免特定边来寻找从起点到各点的次优路径,涉及复杂的数据结构和算法优化。

Description

Gremlins最近在农场上泛滥,它们经常会阻止牛们从农庄(牛棚_1)走到别的牛棚(牛_i的目的地是牛棚_i)。每一个gremlin只认识牛_i并且知道牛_i一般走到牛棚_i的最短路经。所以它们在牛_i到牛棚_i之前的最后一条牛路上等牛_i,当然,牛不愿意遇到Gremlins,所以准备找一条稍微不同的路经从牛棚_1走到牛棚_i,所以,请你为每一头牛_i找出避免gremlin_i的最短路经的长度。
  和以往一样,农场上的M (2 <= M <= 200,000)条双向牛路编号为1..M并且能让所有牛到达它们的目的地,N(3 <= N <= 100,000)个编号为1..N的牛棚。牛路i连接牛棚a_i (1 <= a_i <= N)和b_i (1 <= b_i <= N)并且需要时间t_i (1 <=t_i <= 1,000)通过。没有两条牛路连接同样的牛棚,所有牛路满足a_i!=b_i。在所有数据中,牛_i使用的牛棚_1到牛棚_i的最短路经是唯一的。

Input

  第一行:两个空格分开的数N和M;
  第2..M+1行:三个空格分开的数a_i, b_i,和t_i

Output

  第1..N-1行:第i行包含一个数,从牛棚_1到牛棚_i+1并且避免从牛棚1到牛棚i+1最短路经上最后一条牛路的最少的时间。如果这样的路经不存在,输出-1。

Sample Input

4 5

1 2 2

1 3 2

3 4 4

3 2 1

2 4 3

Sample Output

3

3

6

Hint

【数据范围】
20%的数据满足,N<=200;
50%的数据满足,N<=3000
100%的数据满足,N<=100,000

做这道题之前还不知道有最短路径树这个东西。。。(太菜了233)

既然最短路径是唯一的,显然符合树的性质(可以用反证法证最短路性质)。

题目大意:生成最短路径树后,每次fa[x]->x这条边,用剩余所有边来求1->x的最短路径。

发现是个树,首先就想到树剖。。。

对于一个节点x,有ans=min{dist[u]+dist[v]+w(u,v)-dist[x]},x在lca(u,v)之下,在u,v之上(画图),事实上,也只有满足条件的这种x会被更新到:

1、x在v下面,根据最短路径树的性质,dist[u]+w(u,v)+(v->x)>dist[x]所以不会被更新

2、x在u下面,同上

3、x在lca(u,v)上面,显然= =

发现这个性质之后,就是树剖乱搞了。需要注意的是,u,v会被更新,但lca(u,v)不能被更新。

(码了一个晚自习。。。心力憔悴。。。感动。。。)

#include<bits/stdc++.h>
using namespace std;
#define Inc(i,L,r) for(register int i=(L);i<=(r);++i)
#define Red(i,r,L) for(register int i=(r);i>=(L);--i)
const int N = 1e5+10,E = 2e5+10;
struct Edge{
	int cnt,h[N],w[E<<1],fr[E<<1],to[E<<1],next[E<<1];
	inline void add(int x,int y,int z){
		next[++cnt]=h[x],h[x]=cnt;
		fr[cnt]=x,to[cnt]=y;
		w[cnt]=z;
	}
}e,ex;
bool intree[E<<1];
int n,m;
struct Djkstra{
	struct Node{
		int idx,dist;
		bool operator <(const Node&A) const {
			return dist>A.dist;
		}
	};int fa[N],id[N],dist[N];
	inline void djkstra(){
		memset(dist,63,sizeof(dist));
		priority_queue<Node>Q;
		Q.push((Node){1,dist[1]=0});
		while(!Q.empty()){
			Node x=Q.top();Q.pop();
			for(int p=e.h[x.idx];p;p=e.next[p]){
				int to=e.to[p];if(dist[to]>dist[x.idx]+e.w[p]){
					id[to]=p,fa[to]=x.idx;
					Q.push((Node){to,dist[to]=dist[x.idx]+e.w[p]});
				}
			}
		}
	}
	inline void init(){
		scanf("%d%d",&n,&m);
		e.cnt=1;
		Inc(i,1,m){
			int x,y,z;scanf("%d%d%d",&x,&y,&z);
			e.add(x,y,z),e.add(y,x,z);
		}
	}
}djk;
struct Graph{
	int p[N][18];
	inline void init(){
		Inc(i,1,n)siz[i]=1;
		memset(p,-1,sizeof(p));
		Inc(i,2,n)ex.add(djk.fa[i],i,0);
		Inc(i,2,n)intree[djk.id[i]]=intree[djk.id[i]^1]=1;//树边
	}
	int siz[N],son[N],dep[N];
	int cnt,dfn[N],top[N];
	inline void dfs1(int x,int Fa,int depth){
		for(int P=ex.h[x];P;P=ex.next[P]){
			dfs1(ex.to[P],p[ex.to[P]][0]=x,dep[ex.to[P]]=depth+1);
			siz[x]+=siz[ex.to[P]];
			if(siz[son[x]]<siz[ex.to[P]])son[x]=ex.to[P];
		}
	}
	inline void dfs2(int x,int sp){
		dfn[x]=++cnt;top[x]=sp;
		if(son[x])dfs2(son[x],sp);
		for(int P=ex.h[x];P;P=ex.next[P])if((ex.to[P]^p[x][0])&&(ex.to[P]^son[x]))dfs2(ex.to[P],ex.to[P]);
	}
	inline void ST(){
		int maxdep=log2(n);
		Inc(j,1,maxdep)
			Inc(i,1,n)if(~p[i][j-1])p[i][j]=p[p[i][j-1]][j-1];
	}
	inline int lca(int x,int y){
		if(dep[x]<dep[y])swap(x,y);
		Red(i,log2(dep[x]),0)if(dep[x]-(1<<i)>=dep[y])x=p[x][i];
		if(x==y)return y;
		Red(i,log2(dep[x]),0)if(p[x][i]^p[y][i])x=p[x][i],y=p[y][i];
		return p[x][0];
	}
}g;
struct SegMent{
	struct tree{
		int L,r,mn;
	}t[N<<2];
	#define Ls v<<1
	#define rs v<<1|1
	inline void pushdown(int v){
		t[Ls].mn=min(t[Ls].mn,t[v].mn);
		t[rs].mn=min(t[rs].mn,t[v].mn);
	}
	inline int query(int v,int x){
		if(t[v].L>x||t[v].r<x)return 1<<30;
		if(t[v].L==t[v].r)return t[v].mn;
		pushdown(v);
		return min(query(Ls,x),query(rs,x));
	}
	inline void update(int v,int A,int b,int k){
		if(t[v].L>b||t[v].r<A)return ;
		if(A<=t[v].L&&t[v].r<=b)return t[v].mn=min(t[v].mn,k),void();
		pushdown(v);
		update(Ls,A,b,k),update(rs,A,b,k);
	}
	inline void build(int v,int L,int r){
		t[v]=(tree){L,r,1<<30};
		if(L==r)return ;
		int Mid=L+r>>1;
		build(Ls,L,Mid),build(rs,Mid+1,r);
	}
}t;
inline void modify(int x,int lca,int val){
	int tx=g.top[x];
	while(tx^g.top[lca]){
		t.update(1,g.dfn[tx],g.dfn[x],val);
		x=g.p[tx][0],tx=g.top[x];
	}
	t.update(1,g.dfn[lca]+1,g.dfn[x],val);
}
inline void solv(){
	t.build(1,1,n);
	Inc(i,2,e.cnt)if(!intree[i]){
		int x=e.fr[i],y=e.to[i],lca=g.lca(x,y);
		modify(x,lca,djk.dist[x]+djk.dist[y]+e.w[i]);
		modify(y,lca,djk.dist[x]+djk.dist[y]+e.w[i]);
	}
	Inc(i,2,n){
		int dist=t.query(1,g.dfn[i]);
		cout<<(dist==1<<30?-1:dist-djk.dist[i])<<"\n";
	}
}
int main(){
	djk.init();
	djk.djkstra();
	g.init();
	g.dfs1(1,0,0);
	g.dfs2(1,1);
	g.ST();
	solv();
	return 0;
}

 

### USACO 2025 January Contest Information and Problems For individuals interested in participating or learning about the USA Computing Olympiad (USACO) contests, it's important to understand that specific details regarding future events like the USACO 2025 January contest are not yet available as of now. However, based on previous patterns observed in past competitions such as those mentioned in earlier years[^1], some general expectations can be outlined. #### General Structure of USACO Contests Contests typically consist of several problems categorized by difficulty levels—Bronze, Silver, Gold, and Platinum. Participants solve algorithmic challenges within a limited timeframe using programming languages including C++, Java, Python among others. The exact nature of these questions varies widely but often involves complex algorithms and data structures designed to test both coding skills and problem-solving abilities. #### Preparing for Future Competitions To prepare effectively for upcoming contests similar to what might appear in 2025: - **Practice Regularly**: Engage actively with practice problems from previous contests which cover various topics ranging from basic sorting techniques to advanced graph theory concepts. - **Understand Algorithms & Data Structures**: Deepen knowledge around key areas frequently tested during these exams; this includes dynamic programming, greedy strategies, depth-first search (DFS), breadth-first search (BFS), etc.[^3] - **Participate in Mock Tests**: Join mock testing sessions offered through official platforms or community-driven initiatives where participants attempt solving under exam conditions. Here’s an example code snippet demonstrating how one could approach implementing DFS—a common technique used across many competitive programming tasks: ```cpp void dfs(int node, vector<bool>& visited, const vector<vector<int>>& adjList){ cout << "Visiting Node: " << node << endl; visited[node] = true; // Traverse all adjacent nodes recursively if they haven't been visited already for(auto neighbor : adjList[node]){ if(!visited[neighbor]) dfs(neighbor, visited, adjList); } } ``` --related questions-- 1. What resources exist specifically tailored towards preparing for USACO? 2. How does understanding different types of graphs benefit performance in computational olympiads? 3. Can you provide examples of other international computing olympiads comparable to USACO? 4. In terms of time management, what tips would help maximize efficiency while attempting multiple challenging problems simultaneously?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值