1. 程式人生 > 遊戲資訊 >爐石設計師教你玩遊戲系列,機械法機械騎和詛咒術,你愛玩不玩!

爐石設計師教你玩遊戲系列,機械法機械騎和詛咒術,你愛玩不玩!

例題:bzoj4919大根堆

  洛谷P4577領導集團問題

 

以大根堆為例

就是說我在將它和它的子樹合併的時候
如果他的子樹裡有比它大的,那麼我直接將
大於等於它的第一個數換進去
這樣能保證在序列長度不變的情況下使最大值最小,如果它子樹裡沒有比他大的,直接插入就行
eg : 1 4 7 8 9
我插入6,那麼就會把7換掉,這樣,序列長度還是5不會變,但是如果單獨拿出來看146肯定是比147好的(啟發式合併,將小的向大的合併,所以將最大的根越小越好->更容易合併進大的)但如果用146合併出來的比序列長為5的短,那麼對答案不會有影響
但如果比5長,那麼以6插入肯定比7好

大根堆

點選檢視程式碼
#include <bits/stdc++.h>
#define LL long long 
#define Re register int
#define ki cout << endl 
#define LD double
using namespace std;

namespace kiritokazuto {
	template <typename T> inline void in(T &x) {
		int f = 0; x = 0; char c = getchar();
		while(c < '0' || c > '9')f |= c == '-', c = getchar();
		while(c >= '0' && c <= '9')x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
		x = f ? -x : x;
	}
	
	template <typename T> inline void ot(T x) {
		if(x < 0)putchar('-'), x = -x;
		if(x > 9)ot(x / 10); putchar(x % 10 | '0'); 
	}
	
}
const int maxn = 2e5 + 100;
const int Inf = 1e9;

using namespace kiritokazuto;
//就是想試試 這個 “啟發式合併 ”
//在當前大根堆大小相同的時候,頂點的權值越小,就能合併給更大的大根堆
//啟發式合併 -> 小的往大的裡和 -> 所以不去考慮當前頂點的權值更大 -> 這樣是將別的合併到當前 -> 就不是啟發了(。。。好像倒過來也是?) 
/*
當前點與子樹合併
如果子樹內有比當前點更大的值
答案不會變
直接替換set中比它大與它相鄰的樹
否則直接加進來
*/
/*
set c
產生一個空的set/multiset,不含任何元素

set c(op)
以op為排序準則,產生一個空的set/multiset

//strcut cmp {
	bool operator() (const rec &a, const rec&b) {
		return a.x < b.x || a.x == b.x && a.y < b.y;
	}
} ;
  multiset<rec, cmp> mul;
//

set c1(c2)
產生某個set/multiset的副本,所有元素都被拷貝

set c(beg,end)
以區間[beg,end)內的所有元素產生一個set/multiset

set c(beg,end, op)
以op為排序準則,區間[beg,end)內的元素產生一個set/multiset

c.~set()
銷燬所有元素,釋放記憶體

set<Elem>
產生一個set,以(operator <)為排序準則

set<Elem,op>
產生一個set,以op為排序準則

count (elem)
返回元素值為elem的個數

find(elem)
返回元素值為elem的第一個元素,如果沒有返回end()

lower _bound(elem)
返回元素值為elem的第一個可安插位置,也就是元素值 >= elem的第一個元素位置

upper _bound (elem)
返回元素值為elem的最後一個可安插位置,也就是元素值 > elem 的第一個元素位置

equal_range (elem)
返回elem可安插的第一個位置和最後一個位置,也就是元素值==elem的區間


c.size()
返回當前的元素數量

c.empty ()
判斷大小是否為零,等同於0 == size(),效率更高

c.max_size()
返回能容納的元素最大數量

c1 == c2
判斷c1是否等於c2

c1 != c2
判斷c1是否不等於c2(等同於!(c1==c2))

c1 < c2
判斷c1是否小於c2

c1 > c2
判斷c1是否大於c2

c1 <= c2
判斷c1是否小於等於c2(等同於!(c2<c1))

c1 >= c2
判斷c1是否大於等於c2 (等同於!(c1<c2))

c1 = c2
將c2的元素全部給c1

c1.swap(c2)
將c1和c2 的元素互換

swap(c1,c2)
同上,全域性函式

c.begin()
返回一個隨機存取迭代器,指向第一個元素

c.end()
返回一個隨機存取迭代器,指向最後一個元素的下一個位置

c.rbegin()
返回一個逆向迭代器,指向逆向迭代的第一個元素

c.rend()
返回一個逆向迭代器,指向逆向迭代的最後一個元素的下一個位置

c.insert(elem)
插入一個elem副本,返回新元素位置,無論插入成功與否。

c.insert(pos, elem)
安插一個elem元素副本,返回新元素位置,pos為收索起點,提升插入速度。

c.insert(beg,end)
將區間[beg,end)所有的元素安插到c,無返回值。

c.erase(elem)
刪除與elem相等的所有元素,返回被移除的元素個數。

c.erase(pos)
移除迭代器pos所指位置元素,無返回值。

c.erase(beg,end)
移除區間[beg,end)所有元素,無返回值。

c.clear()
移除所有元素,將容器清空
sets和multisets的迭代器是雙向迭代器
對迭代器操作而言
所有的元素都被視為常數
可以確保你不會人為改變元素值
從而打亂既定順序
所以無法呼叫變動性演算法,如remove()。
必須保證引數有效
迭代器必須指向有效位置
序列起點不能位於終點之後
不能從空容器刪除元素。
*/
#define mulit multiset <int> :: iterator
#define si(x) mul[x].size()
multiset <int> mul[maxn];//存最長序列的尾部 
vector <int> G[maxn];
int n, val[maxn];
void dfs(int u) {
	//如果當前子樹沒有更大的,直接加,就是當前的根節點嚴格大於尾部 
	//否則,當前跟節點小於等於尾部, 則替換大於等於它的第一個數(lower_bound),保證長度最長且權值最小 
	for(Re i = 0, to; i < G[u].size(); i ++) {
		to = G[u][i];
	//	if(to == fa)continue;
		dfs(to);
		if(si(to) > si(u))swap(mul[to], mul[u]); 
		for(mulit it = mul[to].begin(); it != mul[to].end(); it++) mul[u].insert(*it);//mulit預設從小到大 
		mul[to].clear();
	}
	mulit it = mul[u].lower_bound(val[u]);
	if(it != mul[u].end()) mul[u].erase(it);
	mul[u].insert(val[u]);
}

signed main () {
	in(n);
	for(Re i = 1, x; i <= n; i ++) {
		in(val[i]);
		in(x);
		//G[i].push_back(x);
		G[x].push_back(i);
	}
	dfs(1);
	ot(mul[1].size());
	return 0;
} 

領導集團問題

點選檢視程式碼
#include <bits/stdc++.h>
#define LL long long 
#define Re register int
#define ki cout << endl 
#define LD double
using namespace std;

namespace kiritokazuto {
	template <typename T> inline void in(T &x) {
		int f = 0; x = 0; char c = getchar();
		while(c < '0' || c > '9')f |= c == '-', c = getchar();
		while(c >= '0' && c <= '9')x = (x << 1) + (x << 3) + (c ^ 48), c = getchar();
		x = f ? -x : x;
	}
	
	template <typename T> inline void ot(T x) {
		if(x < 0)putchar('-'), x = -x;
		if(x > 9)ot(x / 10); putchar(x % 10 | '0'); 
	}
	
}
const int maxn = 2e5 + 100;
const int Inf = 1e9;

using namespace kiritokazuto;

#define mulit multiset <int> :: iterator
#define si(x) mul[x].size()

multiset <int> mul[maxn];//存最長序列的尾部 
vector <int> G[maxn];
int n, val[maxn];


void dfs(int u) {
	for(Re i = 0, to; i < G[u].size(); i ++) {
		to = G[u][i];
		dfs(to);
		if(si(to) > si(u))swap(mul[to], mul[u]); 
		for(mulit it = mul[to].begin(); it != mul[to].end(); it++) mul[u].insert(*it);//mulit預設從小到大 
	   // mul[to].clear();
	}
	mul[u].insert(val[u]);//先插入,保證有...
	mulit it = mul[u].lower_bound(val[u]);
	if(it != mul[u].begin()) mul[u].erase(--it);//這次該改begin
	
}

signed main () {
  //  freopen("init.in.txt", "r", stdin);
   // freopen("outt.out.txt", "w", stdout);
	in(n);
	for(Re i = 1, x; i <= n; i ++) {
		in(val[i]);
	}
	for(Re i = 2, x; i <= n; i ++) {
		in(x);
		G[x].push_back(i);
	}
	dfs(1);
	ot(mul[1].size());
   // cout << "??";
	return 0;
}