二次联通门 : BZOJ 2002: [Hnoi2010]Bounce 弹飞绵羊
/* BZOJ 2002: [Hnoi2010]Bounce 弹飞绵羊 用LCT维护子树大小 每弹跳一次; 树中+1个节点(本次弹跳终点); 这样弹跳次数就转化为了子树的大小 注意当下标大于N+1时设为N 最初,对于每个反弹装置i,由i向min(n+1,i+k[i])连一条边,i指向min(n+1,i+k[i]) 即这里从树根到往下是弹跳的逆过程 数组版的思路和代码都是参考的xxy dalao */ #include <cstdio> #include <cstdlib> #define Max 200010 void read (int &now) { now = 0; register char word = getchar (); while (word < '0' || word > '9') word = getchar (); while (word >= '0' && word <= '9') { now = now * 10 + word - '0'; word = getchar (); } } inline int min (int a, int b) { return a < b ? a : b; } struct Splay_Tree_Data { int child[2]; int father; int size; int Flandre; }; int N; int next[Max]; Splay_Tree_Data tree[Max]; int data[Max]; inline int swap (int &a, int &b) { int now = a; a = b; b = now; } class Link_Cut_Tree_Type { private : inline void Updata (int now) { tree[now].size = 1; tree[now].size += tree[tree[now].child[0]].size; tree[now].size += tree[tree[now].child[1]].size; } inline void Down (int now) { if (!tree[now].Flandre) return ; tree[now].Flandre ^= 1; tree[tree[now].child[0]].Flandre ^= 1; tree[tree[now].child[1]].Flandre ^= 1; swap (tree[now].child[0], tree[now].child[1]); } bool Is_Root (int now) { return tree[tree[now].father].child[0] != now && tree[tree[now].father].child[1] != now; } inline int Get_Pos (int now) { return tree[tree[now].father].child[1] == now; } inline void Rotate (int now) { int father = tree[now].father; int Grand = tree[father].father; int l, r = 0; l = tree[father].child[0] == now ? 0 : 1; r = l ^ 1; if (!Is_Root (father)) tree[Grand].child[tree[Grand].child[0] != father] = now; tree[father].child[l] = tree[now].child[r]; tree[now].child[r] = father; tree[father].father = now; tree[tree[father].child[l]].father = father; tree[now].father = Grand; Updata (father); } inline void Splay (int now) { int Count = 0; data[++Count] = now; for (int i = now; !Is_Root (i); i = tree[i].father) data[++Count] = tree[i].father; for (int i = Count; i; i --) Down (data[i]); while (!Is_Root (now)) { int father = tree[now].father; int Grand = tree[father].father; if (!Is_Root (father)) { if (tree[father].child[0] == now ^ tree[Grand].child[0] == father) Rotate (now); else Rotate (father); } Rotate (now); Updata (now); } } inline void Access (int now) { int pos = 0; while (now) { Splay (now); tree[now].child[1] = pos; pos = now; now = tree[now].father; } } inline void Make_Root (int now) { Access (now); Splay (now); tree[now].Flandre ^= 1; } inline void Link (int x, int y) { Make_Root (x); tree[x].father = y; Splay (x); } inline void Cut (int x, int y) { Make_Root (y); Access (x); Splay (x); tree[x].child[0] = 0; tree[y].father = 0; } public : inline void Do_First (int x) { Make_Root (N + 1); x ++; Access (x); Splay (x); printf ("%d ", tree[tree[x].child[0]].size); } inline void Do_Second (int x, int y) { x ++; int now = min (N + 1, x + y); Cut (x, next[x]); Link (x, now); next[x] = now; } }; Link_Cut_Tree_Type Make; int M; int main (int argc, char *argv[]) { read (N); int x; for (int i = 1; i <= N; i ++) { read (x); tree[i].father = x + i; tree[i].size = 1; if (tree[i].father > N + 1) tree[i].father = N + 1; next[i] = tree[i].father; } tree[N + 1].size = 1; read (M); for (int x, y, type, i = 1; i <= M; i ++) { read (type); read (x); if (type == 1) Make.Do_First (x); else { read (y); Make.Do_Second (x, y); } } return 0; }
/* 2002: [Hnoi2010]Bounce 弹飞绵羊 Link_Cut_Tree 指针版 mmp, 终于调出来了。。。 指针版比数组版慢300ms 空间比数组版大3倍左右 那么指针和数组的优劣就很清楚了。。。 那么我就写指针了!! */ #include <cstdio> #include <cstdlib> #include <iostream> #define Max 200009 int N; void read (int &now) { now = 0; register char word = getchar (); while (word < '0' || word > '9') word = getchar (); while (word >= '0' && word <= '9') { now = now * 10 + word - '0'; word = getchar (); } } inline int min (int a, int b) { return a < b ? a : b; } struct Splay_Tree_Data { Splay_Tree_Data *child[2]; Splay_Tree_Data *father; int size; int Flandre; Splay_Tree_Data () { size = 1; Flandre = 0; father = NULL; child[0] = child[1] = NULL; } inline void Updata () { size = 1; if (child[0]) size += child[0]->size; if (child[1]) size += child[1]->size; } inline void Down () { if (!Flandre) return ; std :: swap (child[0], child[1]); Flandre = 0; if (child[0]) child[0]->Flandre ^= 1; if (child[1]) child[1]->Flandre ^= 1; } inline int Get_Pos () { return this->father->child[1] == this; } inline int Is_Root () { return !(this->father) || (this->father->child[0] != this && this->father->child[1] != this); } }; Splay_Tree_Data *data[Max]; Splay_Tree_Data *node[Max]; int to[Max]; class Link_Cut_Tree_Type { private : inline void Rotate (Splay_Tree_Data *now) { int pos = now->Get_Pos () ^ 1; Splay_Tree_Data *Father = now->father; Father->child[pos ^ 1] = now->child[pos]; if (now->child[pos]) now->child[pos]->father = Father; now->father = Father->father; if (!(Father->Is_Root ())) now->father->child[Father->Get_Pos ()] = now; Father->father = now; now->child[pos] = Father; Father->Updata (); now->Updata (); } inline void Splay (Splay_Tree_Data *now) { int Count = 0; for (Splay_Tree_Data *Father = now; ; Father = Father->father) { data[++Count] = Father; if (Father->Is_Root ()) break; } for (; Count >= 1; -- Count) data[Count]->Down (); for (; !(now->Is_Root ()); Rotate (now)) if (!(now->father->Is_Root ())) Rotate (now->Get_Pos () == now->father->Get_Pos () ? now->father : now); now->Updata (); } inline void Access (Splay_Tree_Data *now) { for (Splay_Tree_Data *Father = NULL; now; Father = now, now = now->father) { Splay (now); now->child[1] = Father; now->Updata (); } } inline void Make_Root (Splay_Tree_Data *now) { Access (now); Splay (now); now->Flandre ^= 1; } inline void Cut (Splay_Tree_Data *x, Splay_Tree_Data *y) { Make_Root (x); Access (y); Splay (y); x->father = y->child[0] = NULL; y->Updata (); } inline void Link (Splay_Tree_Data *x, Splay_Tree_Data *y) { Make_Root (x); x->father = y; } public : inline void Link (int x, int y) { if (node[x] == NULL) node[x] = new Splay_Tree_Data (); if (node[y] == NULL) node[y] = new Splay_Tree_Data (); node[x]->father = node[y]; } inline void Make_First (int x) { if (node[x] == NULL) node[x] = new Splay_Tree_Data (); if (node[N + 1] == NULL) node[N + 1] = new Splay_Tree_Data; Make_Root (node[N + 1]); Access (node[x]); Splay (node[x]); printf ("%d ", node[x]->child[0]->size); } inline void Make_Second (int x, int y) { if (node[x] == NULL) node[x] = new Splay_Tree_Data; if (node[y] == NULL) node[y] = new Splay_Tree_Data; if (node[min (x + to[x], N + 1)] == NULL) node[min (x + to[x], N + 1)] = new Splay_Tree_Data; Cut (node[x], node[min (x + to[x], N + 1)]); to[x] = y; if (node[min (x + to[x], N + 1)] == NULL) node[min (x + to[x], N + 1)] = new Splay_Tree_Data; Link (node[x], node[min (x + to[x], N + 1)]); } }; Link_Cut_Tree_Type Make; int main (int argc, char *argv[]) { read (N); for (int i = 1; i <= N; i++) { read (to[i]); Make.Link (i, min (i + to[i], N + 1)); } int type, x, y; int M; for (read (M); M--; ) { read (type); if (type == 1) { read (x); Make.Make_First (x + 1); } else { read (x); read (y); Make.Make_Second (++ x, y); } } return 0; }