[LOJ2187] 「SHOI2014」三叉神經樹(LCT)

題意

  • 給你一顆滿三叉樹,每個點權值定義爲所有子節點權值和,葉子節點有一個屬於[0,1][0, 1]的權值,每次修改一個葉子節點的權值,在修改後回答根節點的權值(n5×105n\le5\times10^5)。

首先感謝Hany01的講解,我們首先觀察一下性質,發現每次修改只會修改修改點到根節點路徑的一端前綴,而且這連續一端的位置權值是相同的,那麼我們要找到這個前綴的末尾,也就是第一個和前一段權值不同的位置,我們可以用LCT來維護這棵三叉樹,輔助樹中每個點保存一個點的子樹內是否有權值非00和非11的點,那麼我們修改就很好做了。

首先把修改點Access後Splay到根上,那麼除了它之外它到根路徑上的所有點都會在它的左子樹,我們只需要在Splay上二分查找深度最大的位置即可,找到這個位置之後我們把這個點在原樹中的父親Access,也就相當於斷了它和它子節點之間的聯繫,那麼我們最後Splay修改點,在上面打標記就好了,複雜度O(n log n)O(\text{n log n}),常數似乎還過得去,平均每個點跑了500500毫秒。

#include <bits/stdc++.h>

#define x first
#define y second
#define pb push_back
#define mp make_pair
#define inf (0x3f3f3f3f)
#define mem(a, b) memset(a, b, sizeof(a))
#define Rep(i, a) for (int i = 0; i < a; ++ i)
#define For(i, a, b) for (int i = a; i <= b; ++ i)
#define Forr(i, a, b) for (int i = a; i >= b; -- i)
#define Travel(i, x) for (int i = head[x]; i; i = nxt[i])

using namespace std;

typedef long long ll;
typedef pair<int, int> PII;

template<class T>inline T read(T &_) {
	T __ = getchar(), ___ = 1; _ = 0;
	for (; !isdigit(__); __ = getchar()) if (__ == '-') ___ = -1;
	for (; isdigit(__); __ = getchar()) _ = (_ << 3) + (_ << 1) + (__ ^ 48);
	return _ *= ___;
}

template<class T>inline bool chkmax(T &_, T __) { return _ < __ ? _ = __, 1 : 0; }
template<class T>inline bool chkmin(T &_, T __) { return _ > __ ? _ = __, 1 : 0; }
inline void proStatus() {
	ifstream t("/proc/self/status");
	cerr << string(istreambuf_iterator<char>(t), istreambuf_iterator<char>());
}

const int N = 1.5e6 + 7;

int ch[N][3], fa[N], n, q;

struct Link_Cut_Tree {

#define ls(x) (ch[x][0])
#define rs(x) (ch[x][1])
#define rel(x) (x == rs(fa[x]))

	int ch[N][2], fa[N];
	int Sta[N], a[N], top;
	int not1[N], not2[N], tag[N];

	bool isroot(int x) { return ls(fa[x]) ^ x && rs(fa[x]) ^ x; }

	void add(int x, int z) { 
		tag[x] += z, a[x] += z; 
		if (z > 0) not2[x] = not1[x], not1[x] = 0;
		else not1[x] = not2[x], not2[x] = 0;
	}

	void pushdown(int x) {
		if (tag[x]) {
			if (ls(x)) add(ls(x), tag[x]); 
			if (rs(x)) add(rs(x), tag[x]);
			tag[x] = 0;
		}
	}

	void pushup(int x) {
		not1[x] = not1[ls(x)] | not1[rs(x)] | (a[x] != 1);
		not2[x] = not2[ls(x)] | not2[rs(x)] | (a[x] != 2);
	}

	void rotate(int x) {
		int dad = fa[x], f = rel(x);
		if (!isroot(dad)) ch[fa[dad]][rel(dad)] = x;
		fa[x] = fa[dad], ch[dad][f] = ch[x][f ^ 1];
		fa[ch[x][f ^ 1]] = dad, fa[dad] = x, ch[x][f ^ 1] = dad;
		pushup(dad), pushup(x);
	}

	void splay(int x) {
		Sta[top = 1] = x; 
		for (int i = x; !isroot(i); i = fa[i])
			Sta[++ top] = fa[i];
		while (top) pushdown(Sta[top --]);
		for (; !isroot(x); rotate(x))
			if (!isroot(fa[x]))
				rotate(rel(x) ^ rel(fa[x]) ? x : fa[x]);
	}

	void access(int x) {
		for (int y = 0; x; x = fa[y = x]) 
			splay(x), rs(x) = y, pushup(x);
	}

	int find1(int x) {
		pushdown(x);
		if (!not1[x]) return 0; 
		if (not1[rs(x)]) return find1(rs(x));
		if (a[x] != 1) return x;
		return find1(ls(x));
	}

	int find2(int x) {
		pushdown(x);
		if (!not2[x]) return 0;
		if (not2[rs(x)]) return find2(rs(x));
		if (a[x] != 2) return x; 
		return find2(ls(x));
	}

} T; 

void dfs(int x) { if (x <= n) Rep(j, 3) dfs(ch[x][j]), T.a[x] += T.a[ch[x][j]] >> 1; }

int main() {

	//freopen("2187.in", "r", stdin);
	//freopen("2187.out", "w", stdout);

	read(n);
	For(i, 1, n) Rep(j, 3) {
		read(ch[i][j]);
		fa[ch[i][j]] = T.fa[ch[i][j]] = i;
	}
	For(i, n + 1, n * 3 + 1) 
		read(T.a[i]), ++ T.a[i];
	dfs(1);

	for (int x = read(q), y; q -- ;) {
		read(x), T.access(x), T.splay(x);
		if (T.a[x] > 1) {
			y = T.find2(T.ch[x][0]);
			T.access(fa[y]);
			T.splay(x), T.add(x, -1);
		} else {
			y = T.find1(T.ch[x][0]);
			T.access(fa[y]);
			T.splay(x), T.add(x, 1);
		}
		T.splay(1);
		//cout << T.a[1] << endl;
		printf("%d\n", T.a[1] > 1);
	}

	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章