此题FHQ-Treap居然跑得比Splay还快?

P3224 [HNOI2012] 永无乡

代码如下: ## Splay ```cpp #include <bits/stdc++.h> using namespace std; const int kMaxN = 300000 + 10; const int kMaxLog = 20; const int kInf = 2000000000; struct SplayTree { struct Node { int son[2], fa; int val; int cnt; int siz; }; Node tree[kMaxN * kMaxLog]; int top; inline int NewNode(int val) { tree[++top] = (Node) {0, 0, 0, val, 1, 1}; return top; } inline int NewTree(int val) { int root = NewNode(val); Insert(root, -kInf); Insert(root, kInf); return root; } inline bool GetPos(int x) { return tree[tree[x].fa].son[1] == x; } inline bool GetDir(int x, int val) { return tree[x].val < val; } inline void PushUp(int x) { tree[x].siz = tree[tree[x].son[0]].siz + tree[tree[x].son[1]].siz + tree[x].cnt; } inline void Connect(int son, int fa, bool pos) { if (fa) tree[fa].son[pos] = son; if (son) tree[son].fa = fa; } inline void Rotate(int x) { int y = tree[x].fa; int z = tree[y].fa; bool k = GetPos(x); if (z) tree[z].son[GetPos(y)] = x; tree[x].fa = z; Connect(tree[x].son[!k], y, k); Connect(y, x, !k); PushUp(y); } inline void Splay(int x, int target = 0) { while (tree[x].fa != target) { int y = tree[x].fa; if (tree[y].fa != target) Rotate(GetPos(x) == GetPos(y) ? y : x); Rotate(x); } PushUp(x); } inline int Find(int& root, int val) { int x = root; while (tree[x].val != val && tree[x].son[GetDir(x, val)]) x = tree[x].son[GetDir(x, val)]; Splay(x); root = x; return x; } inline void Insert(int& root, int val) { int x = root, y = 0; while (x && tree[x].val != val) { tree[x].siz++; y = x; x = tree[x].son[GetDir(x, val)]; } if (!x) { x = NewNode(val); Connect(x, y, GetDir(y, val)); } else { tree[x].siz++; tree[x].cnt++; } Splay(x); root = x; } inline int GetRank(int& root, int val) { // Bug!!! // 不能直接这样做!!!若val不存在则会WA /*int x = Find(val); return tree[tree[x].son[0]].siz + 1;*/ int x = root; int ans = 0; while (1) { if (tree[x].val <= val) ans += tree[tree[x].son[0]].siz; if (tree[x].val < val) ans += tree[x].cnt; if (tree[x].val == val || !tree[x].son[GetDir(x, val)]) { Splay(x); root = x; return ans + 1; } else { x = tree[x].son[GetDir(x, val)]; } } } inline int GetKth(int& root, int k) { k++; int x = root; if (tree[x].siz <= k) return -1; while (1) { int lson = tree[x].son[0]; if (k <= tree[lson].siz) { x = lson; } else if (k <= tree[lson].siz + tree[x].cnt) { Splay(x); root = x; return tree[x].val; } else { k -= tree[lson].siz + tree[x].cnt; x = tree[x].son[1]; } } } void Merge(int& root, int x) { if (!x) return; Merge(root, tree[x].son[0]); if (tree[x].val != kInf && tree[x].val != -kInf) Insert(root, tree[x].val); Merge(root, tree[x].son[1]); } void Print(int x) { if (!x) return; Print(tree[x].son[0]); printf("%d ", tree[x].val); Print(tree[x].son[1]); } void PrintTree(const char* message, int root) { printf("%s[ ", message); Print(root); printf("]\n"); } }; struct UnionSet { int father[kMaxN]; UnionSet() { for (int i = 0; i < kMaxN; i++) father[i] = i; } int Find(int x) { if (father[x] == x) { return x; } else { return father[x] = Find(father[x]); } } bool Union(int x, int y) { int i = Find(x); int j = Find(y); father[j] = i; return i != j; } }; SplayTree T; UnionSet S; int n, m, q; int root[kMaxN]; int island[kMaxN]; int main() { scanf("%d %d", &n, &m); for (int i = 1; i <= n; i++) { int a; scanf("%d", &a); root[i] = T.NewTree(a); island[a] = i; } for (int i = 1; i <= m; i++) { int u, v; scanf("%d %d", &u, &v); u = S.Find(u); v = S.Find(v); if (u != v) { // T.PrintTree("Splay u = ", root[u]); // T.PrintTree("Splay v = ", root[v]); if (T.tree[root[u]].siz < T.tree[root[v]].siz) { swap(root[u], root[v]); } T.Merge(root[u], root[v]); // T.PrintTree("Splay u + v = ", root[u]); S.father[v] = u; } } scanf("%d", &q); for (int i = 1; i <= q; i++) { char opt; int x, y; scanf("%s %d %d", &opt, &x, &y); if (opt == 'Q') { int ans = T.GetKth(root[S.Find(x)], y); if (ans == -1) { printf("-1\n"); } else { printf("%d\n", island[ans]); } } else { assert(opt == 'B'); x = S.Find(x); y = S.Find(y); if (x != y) { // T.PrintTree("Splay x = ", root[x]); // T.PrintTree("Splay y = ", root[y]); if (T.tree[root[x]].siz < T.tree[root[y]].siz) { swap(root[x], root[y]); } T.Merge(root[x], root[y]); // T.PrintTree("Splay x + y = ", root[x]); S.father[y] = x; } } } return 0; } ``` ## Treap ```cpp #include <bits/stdc++.h> using namespace std; const int kMaxN = 300000 + 10; const int kMaxLog = 20; const int kInf = 2000000000; struct FhqTreap { struct Node { int val; int l,r; int siz; int pri; }; Node tree[kMaxN * kMaxLog]; int top; inline int NewNode(int val) { top++; tree[top].val = val; tree[top].l = tree[top].r = 0; tree[top].siz = 1; tree[top].pri = rand(); return top; } inline void PushUp(int x) { tree[x].siz = tree[tree[x].l].siz + tree[tree[x].r].siz + 1; } int Merge(int x, int y) { if (!x || !y) { return x | y; } else if (tree[x].pri < tree[y].pri) { tree[x].r = Merge(tree[x].r, y); PushUp(x); return x; } else { tree[y].l = Merge(x, tree[y].l); PushUp(y); return y; } } void SplitByVal(int node, int& x, int& y, int k) { if (!node) { x = y = 0; } else if (tree[node].val <= k) { x = node; SplitByVal(tree[x].r, tree[x].r, y, k); PushUp(x); } else { y = node; SplitByVal(tree[y].l, x, tree[y].l, k); PushUp(y); } } void SplitBySiz(int node, int& x, int& y, int k) { if (!node) { x = y = 0; } else if (tree[tree[node].l].siz + 1 <= k) { x = node; SplitBySiz(tree[x].r, tree[x].r, y, k - tree[tree[x].l].siz - 1); PushUp(x); } else { y = node; SplitBySiz(tree[y].l, x, tree[y].l, k); PushUp(y); } } inline void Insert(int& root, int val) { int x, y; SplitByVal(root, x, y, val); root = Merge(Merge(x, NewNode(val)), y); } inline int GetKth(int& root, int k) { if (k > tree[root].siz) return -1; int x, y; SplitBySiz(root, x, y, k); int node = x; while (tree[node].r) node = tree[node].r; root = Merge(x, y); return tree[node].val; } void MergeTree(int& root, int x) { if (!x) return; MergeTree(root, tree[x].l); Insert(root, tree[x].val); MergeTree(root, tree[x].r); } }; struct UnionSet { int father[kMaxN]; UnionSet() { for (int i = 0; i < kMaxN; i++) father[i] = i; } int Find(int x) { if (father[x] == x) { return x; } else { return father[x] = Find(father[x]); } } bool Union(int x, int y) { int i = Find(x); int j = Find(y); father[j] = i; return i != j; } }; FhqTreap T; UnionSet S; int n, m, q; int root[kMaxN]; int island[kMaxN]; int main() { scanf("%d %d", &n, &m); for (int i = 1; i <= n; i++) { int a; scanf("%d", &a); root[i] = T.NewNode(a); island[a] = i; } for (int i = 1; i <= m; i++) { int u, v; scanf("%d %d", &u, &v); u = S.Find(u); v = S.Find(v); if (u != v) { // T.PrintTree("Splay u = ", root[u]); // T.PrintTree("Splay v = ", root[v]); if (T.tree[root[u]].siz < T.tree[root[v]].siz) { swap(root[u], root[v]); } T.MergeTree(root[u], root[v]); // T.PrintTree("Splay u + v = ", root[u]); S.father[v] = u; } } scanf("%d", &q); for (int i = 1; i <= q; i++) { char opt; int x, y; scanf("%s %d %d", &opt, &x, &y); if (opt == 'Q') { int ans = T.GetKth(root[S.Find(x)], y); if (ans == -1) { printf("-1\n"); } else { printf("%d\n", island[ans]); } } else { assert(opt == 'B'); x = S.Find(x); y = S.Find(y); if (x != y) { // T.PrintTree("Splay x = ", root[x]); // T.PrintTree("Splay y = ", root[y]); if (T.tree[root[x]].siz < T.tree[root[y]].siz) { swap(root[x], root[y]); } T.MergeTree(root[x], root[y]); // T.PrintTree("Splay x + y = ", root[x]); S.father[y] = x; } } } return 0; } ```
by longlongzhu123 @ 2019-04-24 08:56:28


望大佬帮忙解答一下,谢谢!
by longlongzhu123 @ 2019-04-24 08:57:26


手动@[command_block](/space/show?uid=58705) @[lahlah](/space/show?uid=31656) (滑稽) 帮忙看一下?谢谢!
by longlongzhu123 @ 2019-04-24 09:05:38


哪来的这么多操作,我就四个函数 ```cpp int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);} int Ins(int &k,int l,int r,int val){ if(!k)k=++sz; if(l==r)return nd[k].sum=1; if((val<=mid&&Ins(nd[k].ls,l,mid,val))||Ins(nd[k].rs,mid+1,r,val)); return nd[k].sum=nd[nd[k].ls].sum+nd[nd[k].rs].sum,1; } int Ask(int k,int l,int r,int rk){ if(l==r)return l; return nd[nd[k].ls].sum>=rk?Ask(nd[k].ls,l,mid,rk):Ask(nd[k].rs,mid+1,r,rk-nd[nd[k].ls].sum); } int Mrg(int a,int b){ if(!a||!b)return a|b; nd[a].ls=Mrg(nd[a].ls,nd[b].ls),nd[a].rs=Mrg(nd[a].rs,nd[b].rs); nd[a].sum=nd[nd[a].ls].sum+nd[nd[a].rs].sum; return a; } ```
by The_KOG @ 2019-04-24 09:10:40


@[The_KOG](/space/show?uid=98051) 你真的看过讨论标题吗?
by かなで @ 2019-04-24 09:14:53


splay启发式合并的常数好像确实可以抵消掉log的差距
by 142857cs @ 2019-04-24 09:20:48


好像那个常数在OI范围内完全就废了
by 142857cs @ 2019-04-24 09:21:39


@[142857cs](/space/show?uid=35760) emmm? QAQ
by longlongzhu123 @ 2019-04-24 09:23:23


我看了一下原论文,看不懂,但是结论中出现了上万的常数和超过1e9的低次项。。。
by 142857cs @ 2019-04-24 09:24:03


所以说这个结论在OI范围内可能没有意义
by 142857cs @ 2019-04-24 09:25:09


| 下一页