BJOI2010 次小生成树

Description

  小C最近学了很多最小生成树的算法,Prim算法、Kurskal算法、消圈算法等等。
  正当小C洋洋得意之时,小P又来泼小C冷水了。小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说:
  如果最小生成树选择的边集是EM,严格次小生成树选择的边集是ES,那么需要满足:(value(e)表示边e的权值)
      
  这下小C蒙了,他找到了你,希望你帮他解决这个问题。

Input

  输入第一行包含两个整数N和M,表示无向图的点数与边数。
  接下来M行,每行3个数x,y,z表示,点x和点 y之间有一条边,边的权值为z。

Output

  输出包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)

Sample Input

5 6

1 2 1

1 3 2

2 4 3

3 5 4

3 4 3

4 5 6

Sample Output

11

Hint

【数据规模】 
  数据中无向图无自环;
  50%的数据 N≤2000 M≤3000;
  80%的数据 N≤50000 M≤100000;
  100%的数据 N≤100000 M≤300000,边权值非负且不超过 10^9。

maintain(x),旋的那个点只用最后maintain一次。

maintain(x),if多了会很慢。

#include
using namespace std;
const int Maxn=500005;
namespace FastIO{
    const int L=1<<15;
    char buffer[L],*S,*T;
    inline char gc(){
		if(S==T){T=(S=buffer)+fread(buffer,1,L,stdin);
		if(S==T)return EOF;}return *S++;
	}
    inline int getint(){
		register char c;register int x=0,f=1;
		for(c=gc();c<'0'||c>'9';c=gc()) if(c=='-')f=-1;
		while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c-'0'),c=gc();
		return x*f;
	}
}
using FastIO::getint;
using FastIO::gc;
struct Splay{
	int rev[Maxn],prt[Maxn],ch[2][Maxn];
	int stk[Maxn],val[Maxn],fir[Maxn],sec[Maxn];
	#define ls(x) ch[0][x]
	#define rs(x) ch[1][x]
	bool isroot(int x){
		return (ls(prt[x])^x)&&(rs(prt[x])^x);
	}
	void maintain(int x){
		fir[x]=x;sec[x]=-1;
		fir[x]=val[fir[ls(x)]]<=val[fir[x]]?fir[x]:fir[ls(x)];
		fir[x]=val[fir[rs(x)]]<=val[fir[x]]?fir[x]:fir[rs(x)];
		if(val[fir[ls(x)]]^val[fir[x]]){
			sec[x]=~sec[x]?sec[x]:fir[ls(x)];
			sec[x]=val[fir[ls(x)]]<=val[sec[x]]?sec[x]:fir[ls(x)];
		}
		if(val[sec[ls(x)]]^val[fir[x]]){
			sec[x]=~sec[x]?sec[x]:sec[ls(x)];
			sec[x]=val[sec[ls(x)]]<=val[sec[x]]?sec[x]:sec[ls(x)];
		}
		if(val[fir[x]]^val[x]){
			sec[x]=~sec[x]?sec[x]:x;
			sec[x]=val[x]<=val[sec[x]]?sec[x]:x;
		}
		if(val[fir[rs(x)]]^val[fir[x]]){
			sec[x]=~sec[x]?sec[x]:fir[rs(x)];
			sec[x]=val[fir[rs(x)]]<=val[sec[x]]?sec[x]:fir[rs(x)];
		}
		if(val[sec[rs(x)]]^val[fir[x]]){
			sec[x]=~sec[x]?sec[x]:sec[rs(x)];
			sec[x]=val[sec[rs(x)]]<=val[sec[x]]?sec[x]:sec[rs(x)];
		}	
	}
	void rotate(int x){
		int f=prt[x],gf=prt[f],t=rs(f)==x,son=ch[!t][x];
		if(!isroot(f))ch[rs(gf)==f][gf]=x;prt[x]=gf;
		ch[t][prt[son]=f]=son,maintain(f);
		ch[!t][prt[f]=x]=f; return ;
	}
	void pushdown(int x){
		if(rev[x]){
			rev[ls(x)]^=1,rev[rs(x)]^=1;
			swap(ls(x),rs(x));
			rev[x]^=1;
		}
	}
	void splay(int x){
		stk[++stk[0]]=x;for(int i=x;!isroot(i);i=prt[i])stk[++stk[0]]=prt[i];
		while(stk[0])pushdown(stk[stk[0]--]);
		for(;!isroot(x);rotate(x)){
			if(!isroot(prt[x])&&((rs(prt[prt[x]])==prt[x])==(rs(prt[x])==x)))rotate(x);//oj去掉结构体直接单旋过 
		}
		maintain(x);
	}
};
struct LinkCutTree{
	Splay s;
	void access(int x){
		for(int lastx=0;x;lastx=x,x=s.prt[x])
			s.splay(x),s.rs(x)=lastx,s.maintain(x);
	}
	void makeroot(int x){
		access(x),s.splay(x),s.rev[x]^=1;
	}
	void link(int x,int y){
		makeroot(x),s.prt[x]=y;
	}
	void split(int x,int y){
		makeroot(x),access(y),s.splay(y);
	}
}lct;
struct Edge{
	int x,y,v;
	bool operator <(const Edge&rhs)const{
		return v

 

你可能感兴趣的:(数据结构,LCT)