BZOJ4538 HNOI2016 網路
阿新 • • 發佈:2019-01-14
這道題解法很多,我知道三種:點分治;利用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好叼啊