【BZOJ-2888】資源運輸 LCT + 啓發式合併

2888: 資源運輸

Time Limit: 10 Sec  Memory Limit: 128 MB
Submit: 63  Solved: 33
[Submit][Status][Discuss]

Description

       小Y盯上了最近發行的即時戰略遊戲——ResourceTransport。但在前往通關之路的道路上,一個小遊戲擋住了小Y的步伐。「國家的本質是生產與收集資源」是整款遊戲的核心理念,這個小遊戲也不例外。簡單的說,用戶須要管理一個國家,使其繁榮富強。
       一個國家含有N個城市,遊戲開始時城市間沒有任何道路。城市能夠經過高速公路鏈接。爲了減小建設費用,每對城市間最多存在一條路徑。
       小Y擁有極強的遊戲天賦,很快就把全部城市的生產能力提到了滿級,把高速公路的建設費用修改爲了0。
悲劇的是,對於每一個連通的城市羣,都要把該城市羣中的某個城市設立成資源集合處,小Y把這件事忘了;更悲劇的是,建造高速公路這件事,小Y也忘了。
可小Y是個完美主義者,他請來了你幫他設立資源集合處,本身負責建造高速公路。 假設連通城市羣中的某個城市 i 到該城市羣的資源集合處最少須要通過Di 條高速公路,那麼總運輸費用爲Sigma(Di)你須要在每一個連通城市羣中設立一個資源集合處,使得總費用最小。小 Y 有時會向你詢問此時最小的總費用
問題很簡單,麻煩的是小Y會在你好不容易算出最小總費用時建造一條新的高速公路。因爲每一個連通的城市羣只能有一個資源集合處,因此最小總費用又得從新計算,這可真是個苦差事……

Input

第一行兩個整數N,M分別表示國家中的城市數與小Y的操做數。
接下來M行,每行可能爲:
       1.A x y:表示在城市x和城市y間建造一條高速公路,保證此操做出現N-1次;
       2.Q:表示小Y詢問此時的最小總費用。

Output

       對於每一個Q操做,單獨輸出一行一個整數Ans,表示所求的答案。

Sample Input

8 10
Q
A 1 2
A 4 5
A 6 7
A 3 4
Q
A 2 5
A 6 8
A 4 6
Q

Sample Output

0
4
12
【樣例解釋】
1.開始全部城市互不聯通,每一個城市都是資源集合處,費用爲0;
2.後來分別把城市一、城市四、城市七、城市8設立爲資源集合處,費用爲4;
3.最後把城市4設立爲資源集合處,費用爲12。

HINT

N<=40000,M<=80000php

Source

Solution

首先能夠發現,對於森林中的每棵樹,資源集合處都應該是重心。ios

因此對森林,維護每一個樹的重心。數組

問題在於合併兩棵樹時快速獲得新樹的重心,只能暴力重構。spa

不過考慮把小的一棵樹拆開,一個一個點的加入大的一棵樹中,這樣就能夠獲得新樹的重心了(保持原有重心或者向加點方向移動一步)。blog

維護答案須要維護子樹到重心的距離和,那麼加入一個新點,至關於鏈上加一個等差數列。遊戲

等差數列標記顯然是能夠合併的,注意下放的時候,若是向左子樹下放則須要加上右子樹的貢獻,由於LCT中的右子樹是其左子樹的後代。ip

這樣啓發式合併的複雜度就是$O(Nlog^{2}N)$,不過直接寫數組的常數有點略大會TLE..因此改爲告終構體。資源

Code

#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
inline int read()
{
	int x=0,f=1; char ch=getchar();
	while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
	while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
	return x*f;
}

#define MAXN 40010

int N,M,ans;

struct EdgeNode{
	int next,to;
}edge[MAXN<<1];
int head[MAXN],cnt=1;
inline void AddEdge(int u,int v) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v;}
inline void InsertEdge(int u,int v) {AddEdge(u,v); AddEdge(v,u);}

namespace LCT{
	
	int sz;
	struct LCTNode{
		int son[2],fa,size,tag,val,a1,d,sum;
	}t[MAXN];
	
	inline bool isroot(int x) {return t[t[x].fa].son[0]!=x&&t[t[x].fa].son[1]!=x || !t[x].fa;}
	
	inline void Update(int x) {if (!x) return; t[x].size=t[t[x].son[0]].size+t[t[x].son[1]].size+1;}
	
	inline void Modify(int x,int v) {if (!x) return; t[x].tag+=v; t[x].val+=v;}
	
	inline void Change(int x,int _a1,int _d) {if (!x) return; t[x].a1+=_a1; t[x].d+=_d; t[x].sum+=_a1+t[t[x].son[1]].size*_d;}
	
	inline void Pushdown(int x)
	{
		if (!x) return;
		if (t[x].tag) Modify(t[x].son[0],t[x].tag),Modify(t[x].son[1],t[x].tag),t[x].tag=0;
		if (t[x].d) Change(t[x].son[0],t[x].a1+(t[t[x].son[1]].size+1)*t[x].d,t[x].d),Change(t[x].son[1],t[x].a1,t[x].d),t[x].a1=t[x].d=0;	
	}
	
    inline void Rotate(int x)
    {
        int y=t[x].fa,w=t[y].son[1]==x,z=t[y].fa;
        t[y].son[w]=t[x].son[w^1];
        if (t[x].son[w^1]) t[t[x].son[w^1]].fa=y;
        if (t[z].son[0]==y) t[z].son[0]=x; else if (t[z].son[1]==y) t[z].son[1]=x;
        t[x].fa=z; t[y].fa=x; t[x].son[w^1]=y;
		Update(y);
    }
    
    int stack[MAXN];
    inline void Splay(int x)
    {
        int tmp=x,top=0,y; stack[++top]=x;
        while (!isroot(tmp)) stack[++top]=tmp=t[tmp].fa;
        while (top) Pushdown(stack[top--]);
        while (!isroot(x)) {
            y=t[x].fa;
            if (!isroot(y))
                if ((t[t[y].fa].son[0]==y)^(t[y].son[0]==x)) Rotate(x);
                	else Rotate(y);
                Rotate(x);
        }
        Update(x);
    }	
    
    inline void Access(int x) {for (int y=0; x; y=x,x=t[x].fa) Splay(x),t[x].son[1]=y,Update(x);}
	
	inline int Root(int x) {Access(x); Splay(x); while(t[x].son[0]) x=t[x].son[0]; return x;}
	
	inline void Add(int x,int y)
	{
		t[x].fa=y; t[x].son[0]=t[x].son[1]=t[x].val=t[x].tag=t[x].sum=t[x].a1=t[x].d=0; t[x].size=1;
		y=Root(y); Access(x); Splay(y); 
		Modify(y,1); Change(y,0,1);
		for (x=t[y].son[1]; t[x].son[0]; x=t[x].son[0]);
		Splay(x); int v1=t[y].val,v2=t[x].val;
		if ((v2<<1)>v1) {
			t[x].val=v1; t[y].val-=v2;
			t[y].sum-=t[x].sum+v2; t[x].sum+=t[y].sum+v1-v2;
			Access(x); Splay(y); t[y].son[0]=x; t[y].son[1]=0;
		}
	} //push x into y
	
	inline void DFS(int now,int last)
	{
		Add(now,last); 
		for (int i=head[now]; i; i=edge[i].next)
			if (edge[i].to!=last)
				DFS(edge[i].to,now);
	}
	
	inline void Link(int x,int y)
	{
		int rx=Root(x),ry=Root(y);
		ans-=t[rx].sum+t[ry].sum;
		if (t[rx].val<t[ry].val) swap(x,y);
		DFS(y,x); InsertEdge(x,y);
		ans+=t[Root(x)].sum;
	}

}	

int main()
{
	
	N=read(),M=read();
	for (int i=1; i<=N; i++) LCT::t[i].val=LCT::t[i].size=1;
	
	while (M--) {
		char opt[2]; scanf("%s",opt+1);
		switch (opt[1]) {
			int x,y;
			case 'A' : x=read(),y=read(); LCT::Link(x,y); break;
			case 'Q' : printf("%d\n",ans); break;
		}
		
	}
	
	return 0;
}
相關文章
相關標籤/搜索