[HNOI2010]彈飛綿羊 (平衡樹,LCT動態樹)

題面

題解 

因爲每個點都只能向後跳到一個唯一的點,但可能不止一個點能跳到後面的某個相同的點,

所以我們把它抽象成一個森林。(思考:爲什麼是森林而不是樹?)

子節點可以跳到父節點,根節點再跳就跳飛了。

由於我們發現有一些父子關係要變,所以不能用樹鏈剖分等靜態的數據結構,可以用LCT(Link-Cut-Tree 聯-切-樹,即動態樹,支持動態修改父子關係)。

但是當我們詢問答案的時候,我們發現wa了,那是因爲我們詢問的是x點到根的路徑上的點數,但是各種LCT操作已經把原先的根不知換到那裏去了,所以整個過程中,我們要維護樹的根不變

這個其實很簡單,每次進行涉及換根操作時,我們都把原先的根存一下(Findroot()/Find()),操作完後,再把根換回去(Makeroot()),全過程中,當發現x + kx大於n時,就Makeroot(x)。

(由於是道數據結構題,題解寫得真的不是很長,請儘量理解吧)

CODE

LCT建議壓行,不僅好改而且好看。

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
#include<cmath>
#include<algorithm>
#include<map>
#include<stack>
#define LL long long
#define MAXN 2000050
#define DB double
#define lowbit(x) ((-x & x))
#define rg register
using namespace std;
inline LL read() {
	LL f = 1,x = 0;char s = getchar();
	while(s < '0' || s > '9') {if(s == '-') f = -1;s = getchar();}
	while(s >= '0' && s <= '9') {x = x * 10 + s - '0';s = getchar();}
	return x * f;
}
int n;
int m,i,j,s,o,k;
//--------------------------key numbers-------------------------------
struct tr{
	int s[2],fa;
	int siz;
	int nm,as;
	int lzn,lzr;// lzn其實不需要,只是懶得刪
	tr(){s[0] = s[1] = 0;nm = 0;siz = 0;lzn = lzr = 0;as = 0;}
}tre[MAXN];int cnt_splay = 0,st[MAXN],sttop = 0;
inline int newnode(int nm) {
	int ct = ++cnt_splay;
	tre[ct] = tr();
	tre[ct].nm = nm;
	tre[ct].as = nm;
	tre[ct].siz = 1;
	return ct;
}
inline bool isroot(int x) {
	if(tre[tre[x].fa].s[1] == x || tre[tre[x].fa].s[0] == x) return 0;
	return 1;
}
inline void update(int x) {
	int l=tre[x].s[0],r = tre[x].s[1];tre[0] = tr();
	tre[x].as = tre[x].nm + tre[l].as + tre[r].as;
	tre[x].siz = tre[l].siz + tre[r].siz + 1;
	tre[l].fa = x;tre[r].fa = x;tre[0] = tr();
}
inline void changer(int x) {swap(tre[x].s[0],tre[x].s[1]); tre[x].lzr ^= 1;}
inline void pushdown(int x) {
	if(!x) return ;
	if(tre[x].lzr) {
		changer(tre[x].s[0]);
		changer(tre[x].s[1]);
		tre[x].lzr = 0;
	}return ;
}
inline void pushup(int x) {
	sttop = 0;st[++sttop] = x;
	for(int f = x;!isroot(f); f = tre[f].fa) st[++sttop] = tre[f].fa;
	while(sttop) pushdown(st[sttop --]);
}
inline void rotate(int x) {
	int y = tre[x].fa,z = tre[y].fa;
	int d = (tre[y].s[1] == x);
	if(!isroot(y)) tre[z].s[tre[z].s[1] == y] = x;
	tre[x].fa = z;
	tre[y].s[d] = tre[x].s[d^1];
	if(tre[y].s[d]) tre[tre[y].s[d]].fa = y;
	tre[x].s[d^1] = y;
	tre[y].fa = x;
	update(y);update(x);
}
inline void splay(int x) {
	pushup(x);
	while(!isroot(x)) {
		int y = tre[x].fa,z = tre[y].fa;
		if(!isroot(y)) {
			if((tre[y].s[1] == x) ^ (tre[z].s[1] == y)) rotate(x);
			else rotate(y);
		}
		rotate(x);
	}
	update(x); return ;
}
inline void wash() {splay(rand() % cnt_splay + 1);}
//--------------------------splay-------------------------------------
inline void Access(int x) {
	for(int pre = 0; x; pre = x,x = tre[x].fa) {
		splay(x);
		tre[x].s[1] = pre;
		update(x);
	}return ;
}
inline void Maketop(int x) {Access(x);splay(x);}
inline void Makeroot(int x) {Access(x); splay(x); changer(x);}
inline int  Findroot(int x) {for(Maketop(x); tre[x].s[0]; x = tre[x].s[0]); splay(x); return x;}
inline void Change(int x,int nm) {Maketop(x); tre[x].nm = nm; update(x);}
//##### no Makeroot() inside
inline void Link(int x,int y) {Makeroot(x); tre[x].fa = y;}
inline void Cut(int x,int y) {Makeroot(x); Maketop(y); tre[y].s[0] = tre[x].fa = 0; update(y); pushup(x);}
inline int  Getline(int x,int y) {Makeroot(x); Maketop(y); update(y); return y;}
inline bool Haveedge(int x,int y) {Makeroot(x); Maketop(y); return tre[x].fa == y;}
//-------------------------Link Cut Tree------------------------------
char ss[20];
int ki[MAXN];
int main() {
	n = read();
	cnt_splay = 0;
	for(int i = 1;i <= n+3;i ++) {
		newnode(1);
	}
	for(int i = 1;i <= n;i ++) {
		ki[i] = read();
		if(i + ki[i] <= n) Link(i,i + ki[i]);
		else Makeroot(i);
	}
	m = read();
	while(m --) {
		k = read();
		if(k == 1) {
			s = read() + 1;
			Access(s);
			splay(s);
			printf("%d\n",tre[s].as);
		}
		else if(k == 2) {
			s = read() + 1;o = read();
			if(s + ki[s] <= n) {
				int v = s + ki[s];
				int rt = Findroot(v);
				Cut(s,v);
				Makeroot(rt);
			}
			ki[s] = o;
			if(s + ki[s] > n) Makeroot(s);
			else {
				int rt = Findroot(s + ki[s]);
				Link(s,s + ki[s]);
				Makeroot(rt);
			}
		}
	}
	return 0;
}

 

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