1. 程式人生 > >BZOJ4538 HNOI2016 網路

BZOJ4538 HNOI2016 網路

這道題解法很多,我知道三種:點分治;利用DFS序轉化為平面內求最值問題;直接搞

這題考場上剛了很久,但是最終沒有寫出來,於是導致第一天雪崩,考試一定要冷靜。

做的時候想到了前兩種方法,因為第二種比較直觀,於是選擇了第二種。

但是發現這東西直接維護的話:

1.用3個樹套在一起(堆可以用兩個優先佇列做出來,但是STL似乎很慢),很難寫,加複雜度很嚇人。

2.用KD-TREE,但是這東西我不熟練,複雜度也不會證明(@Claris說是根號M的)。

又發現題目沒有要求強制線上,於是準備用CDQ分治+掃描線+線段樹,貌似很容易就會想到這個思路。但寫起來發現不是很好寫,調了3個小時還沒搞出來於是很不甘心,結果最終都沒有做出來,浪費了大量的時間。

考完以後看網上的題解卻發現考試的時候太naive忽視了最暴力最直觀的解法。

插入一條線段,相當於在樹上不在這個線段上的點都插入一個值。而線段可以輕鬆剖分成logN個區間,那麼取補集,可以同樣轉化為logN個區間。那麼再套上一個樹套樹(一個樹可以用stl)就能直接修改了。

這種方法最慢的測試點是1.6秒,而TL是2秒。因為樹鏈剖分的常數特別小才能通過,如果是前面的3個樹套在一起肯定就過不了了。

該方法程式碼如下:

/*
* @Author: 逸閒
* @Date:   2016-04-19 15:24:06
* @Last Modified by:   逸閒
* @Last Modified time: 2016-04-19 16:12:03
*/

#include "cstdio"
#include "cstdlib"
#include "iostream"
#include "algorithm"
#include "cstring"
#include "queue"

using namespace std;

#define INF 0x3F3F3F3F
#define MAX_SIZE 200005
#define Eps
#define Mod
#define Get(x, a) (x ? x -> a : 0)
#define L(i) (i ? Mid + 1 : Left)
#define R(i) (i ? Right : Mid)
#define Travel(x) for(typeof(x.begin()) it = x.begin(); it != x.end(); ++it)

inline int Get_Int()
{
	int Num = 0, Flag = 1;
	char ch;
	do
	{
		ch = getchar();
		if(ch == '-')
			Flag = -Flag;
	}
	while(ch < '0' || ch > '9');
	do
	{
		Num = Num * 10 + ch - '0';
		ch = getchar();
	}
	while(ch >= '0' && ch <= '9');
	return Num * Flag;
}

class Heap
{
public:
	priority_queue<int> Exist, Deleted;

	inline void Push(int Value)
	{
		Exist.push(Value);
	}

	inline void Erase(int Value)
	{
		Deleted.push(Value);
	}

	inline int Top()
	{
		while(!Deleted.empty() && Exist.top() == Deleted.top())
		{
			Exist.pop();
			Deleted.pop();
		}
		if(Exist.empty())
			return -1;
		else
			return Exist.top();
	}
};

namespace Segment_Tree
{
	Heap Max[MAX_SIZE * 4];

	void Modify(int Now, int left, int right, int Value, int Flag, int Left, int Right)
	{
		if(left == Left && right == Right)
		{
			if(!Flag)
				Max[Now].Push(Value);
			else
				Max[Now].Erase(Value);
			return;
		}
		int Mid = Left + Right >> 1;
		if(left > Mid || right <= Mid)
		{
			int i = left > Mid;
			Modify(Now << 1 | i, left, right, Value, Flag, L(i), R(i));
			return;
		}
		Modify(Now << 1, left, Mid, Value, Flag, L(0), R(0));
		Modify(Now << 1 | 1, Mid + 1, right, Value, Flag, L(1), R(1));
	}

	int Query(int Now, int Position, int Left, int Right)
	{
		int Ans = Max[Now].Top();
		if(Left != Right)
		{
			int Mid = Left + Right >> 1, i = Position > Mid;
			Ans = max(Ans, Query(Now << 1 | i, Position, L(i), R(i)));
		}
		return Ans;
	}
}

class Edge
{
public:
	int To, Next;
}Edges[MAX_SIZE * 2];

int N, Q, Total;
int Front[MAX_SIZE], A[MAX_SIZE], B[MAX_SIZE], C[MAX_SIZE];

inline void Add_Edge(int From, int To)
{
	Edges[++Total].To = To;
	Edges[Total].Next = Front[From];
	Front[From] = Total;
}

inline void Add_Edges(int From, int To)
{
	Add_Edge(From, To);
	Add_Edge(To, From);
}

vector< pair<int, int> > temp;

namespace Heavy_Light_Decomposition
{
	int Total;
	int Father[MAX_SIZE], Size[MAX_SIZE], Son[MAX_SIZE], Top[MAX_SIZE], DFN[MAX_SIZE], Position[MAX_SIZE], Depth[MAX_SIZE];

	void DFS1(int Now)
	{
		Size[Now] = 1;
		Depth[Now] = Depth[Father[Now]] + 1;
		for(int i = Front[Now]; i; i = Edges[i].Next)
			if(Edges[i].To != Father[Now])
			{
				Father[Edges[i].To] = Now;
				DFS1(Edges[i].To);
				if(Size[Edges[i].To] > Size[Son[Now]])
					Son[Now] = Edges[i].To;
				Size[Now] += Size[Edges[i].To];
			}
	}

	void DFS2(int Now, int top)
	{
		Top[Now] = top;
		DFN[Now] = ++Total;
		Position[Total] = Now;
		if(Son[Now])
			DFS2(Son[Now], top);
		for(int i = Front[Now]; i; i = Edges[i].Next)
			if(Edges[i].To != Father[Now] && Edges[i].To != Son[Now])
				DFS2(Edges[i].To, Edges[i].To);
	}

	inline void Build()
	{
		DFS1(1);
		DFS2(1, 1);
	}

	inline void Get_Interval(int x, int y)
	{
		while(Top[x] != Top[y])
		{
			if(Depth[Top[x]] < Depth[Top[y]])
				swap(x, y);
			temp.push_back(make_pair(DFN[Top[x]], DFN[x]));
			x = Father[Top[x]];
		}
		if(Depth[x] < Depth[y])
			swap(x, y);
		temp.push_back(make_pair(DFN[y], DFN[x]));
	}
}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("network.in", "r", stdin);
	freopen("network.out", "w", stdout);
#endif
	cin >> N >> Q;
	for(int i = 1; i < N; ++i)
		Add_Edges(Get_Int(), Get_Int());
	Heavy_Light_Decomposition::Build();
	for(int i = 1; i <= Q; ++i)
	{
		int Op = Get_Int();
		if(Op == 2)
			printf("%d\n", Segment_Tree::Query(1, Heavy_Light_Decomposition::DFN[Get_Int()], 1, N));
		else
		{
			int x, y, v;
			if(Op == 0)
			{
				A[i] = x = Get_Int();
				B[i] = y = Get_Int();
				C[i] = v = Get_Int();
			}
			else
			{
				int k = Get_Int();
				x = A[k];
				y = B[k];
				v = C[k];
			}
			temp.clear();
			Heavy_Light_Decomposition::Get_Interval(x, y);
			sort(temp.begin(), temp.end());
			int Last = 1;
			Travel(temp)
			{
				if(it -> first > Last)
					Segment_Tree::Modify(1, Last, it -> first - 1, v, Op, 1, N);
				Last = it -> second + 1;
			}
			if(Last <= N)
				Segment_Tree::Modify(1, Last, N, v, Op, 1, N);
		}
	}
	fclose(stdin);
	fclose(stdout);
	return 0;
}

PS:HLD好叼啊