1. 程式人生 > >[Beijing2010組隊]次小生成樹Tree

[Beijing2010組隊]次小生成樹Tree

list div %d nod include opera ace radius ott

小C最近學了很多最小生成樹的算法,Prim算法、Kurskal算法、消圈算法等等。正當小C洋洋得意之時,小P又來潑小C冷水了。小P說,讓小C求出一個無向圖的次小生成樹,而且這個次小生成樹還得是嚴格次小的,也就是說:如果最小生成樹選擇的邊集是EM,嚴格次小生成樹選擇的邊集是ES,那麽需要滿足:(value(e)表示邊e的權值) \sum_{e \in E_M}value(e)<\sum_{e \in E_S}value(e)eEM??value(e)<eES??value(e)

這下小 C 蒙了,他找到了你,希望你幫他解決這個問題。

輸入輸出格式

輸入格式:

第一行包含兩個整數N 和M,表示無向圖的點數與邊數。 接下來 M行,每行 3個數x y z 表示,點 x 和點y之間有一條邊,邊的權值為z。

輸出格式:

包含一行,僅一個數,表示嚴格次小生成樹的邊權和。(數據保證必定存在嚴格次小生成樹)

輸入輸出樣例

輸入樣例#1:
5 6
1 2 1 
1 3 2 
2 4 3 
3 5 4 
3 4 3 
4 5 6 
輸出樣例#1: 復制
11

說明

數據中無向圖無自環; 50% 的數據N≤2 000 M≤3 000; 80% 的數據N≤50 000 M≤100 000; 100% 的數據N≤100 000 M≤300 000 ,邊權值非負且不超過 10^9 。

跑個最小生成樹然後LCA維護路徑最大和次大(嚴格)邊即可,利用了最小生成樹的環性質。

(我就想請問出題人忘了給邊排序是怎麽能過樣例hhhh,mdzz查錯了一個點最後發現沒給邊排序)

code:

#include<bits/stdc++.h>
#define ll long long
#define maxn 100005
using namespace std;
ll base=0;
struct lines{
	int u,v,w;
	bool operator <(const lines &U)const{
		return w<U.w;
	}
}l[maxn*3];
struct node{
	int m,cm;
	node operator +(const node &u)const{
		node r;
		r.m=max(m,u.m);
		r.cm=max(cm,u.cm);
	    if(m<r.m) r.cm=max(r.cm,m);
	    if(u.m<r.m) r.cm=max(r.cm,u.m);
	    return r;
	}
};
const int inf=1e9;
bool choose[maxn*3];
int ci[30],ans=inf;
int to[maxn*2],ne[maxn*2];
int val[maxn*2],cnt=0,n,m;
int f[maxn][20];
node g[maxn][20];
int hd[maxn],p[maxn],dep[maxn];

int ff(int x){
	return p[x]==x?x:(p[x]=ff(p[x]));
}

inline void add(lines e){
	to[++cnt]=e.v,ne[cnt]=hd[e.u],val[cnt]=e.w,hd[e.u]=cnt;
	to[++cnt]=e.u,ne[cnt]=hd[e.v],val[cnt]=e.w,hd[e.v]=cnt;	
}

inline void kruscal(){
	for(int i=1;i<=n;i++) p[i]=i;
	int fa,fb,tot=0;
	sort(l+1,l+m+1);
	
	n--;
	for(int i=1;i<=m;i++){
		fa=ff(l[i].u),fb=ff(l[i].v);
		if(fa!=fb){
			tot++,choose[i]=1;
			base+=(ll)l[i].w;
			add(l[i]),p[fa]=fb;
			if(tot==n) break;
		}
	}
	n++;
}

void dfs(int x,int fa){
	for(int i=1;ci[i]<=dep[x];i++){
		g[x][i]=g[x][i-1]+g[f[x][i-1]][i-1];
		f[x][i]=f[f[x][i-1]][i-1];
	}
	
	for(int i=hd[x];i;i=ne[i]) if(to[i]!=fa){
		dep[to[i]]=dep[x]+1;
		f[to[i]][0]=x;
		g[to[i]][0]=(node){val[i],0};
		dfs(to[i],x);
	}
}

inline node LCAMAX(int x,int y){
	if(dep[x]<dep[y]) swap(x,y);
	int dt=dep[x]-dep[y];
	node an=(node){0,0};
	for(int i=0;ci[i]<=dt;i++) if(ci[i]&dt){
		an=an+g[x][i];
		x=f[x][i];
	}
	
	if(x==y) return an;
	
	int s=log(dep[x])/log(2)+1;
	for(;s>=0;s--){
		if(ci[s]>dep[x]) continue;
		if(f[x][s]!=f[y][s]){
			an=an+g[x][s]+g[y][s];
			x=f[x][s],y=f[y][s];
		}
	}
	
	return an+g[x][0]+g[y][0];
}

inline void solve(){
	dep[1]=0;
	dfs(1,0);
	
	node tmp;
	for(int i=1;i<=m;i++) if(!choose[i]){
		tmp=LCAMAX(l[i].u,l[i].v);
//		printf("%d %d %d\n",i,tmp.m,tmp.cm);
		if(tmp.m<l[i].w) ans=min(ans,l[i].w-tmp.m);
		else ans=min(ans,l[i].w-tmp.cm);
	}
}

int main(){
	ci[0]=1;
	for(int i=1;i<=20;i++) ci[i]=ci[i-1]<<1;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++) scanf("%d%d%d",&l[i].u,&l[i].v,&l[i].w);
	
	kruscal();
	solve();
	
	cout<<(ll)ans+base<<endl;
	return 0;
}

  

[Beijing2010組隊]次小生成樹Tree