NTOJ 1013 [RYOI2018ER]变成

给定两棵有根树$T_a,T_b$,你可以在$T_a$上进行旋转(就是$splay,treap$那种)

要求把$T_a$转成$T_b$,旋转次数不超过$10^6$

数据保证点数不超过$10^5$

由于是旋转操作,因此并不影响中序遍历结果

也就是说$T_a$和$T_b$的$dfs$序上下标相同的点是配对的

因此只需要在$T_b$上$dfs$,假设当前访问到了$u$,只需要将$u$在$T_a$中的配对点$splay$到$u$所对应的点就行了(之后这个配对点不会再被旋转)

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 const int N = 1e5 + 10;
 4 int n, tot, ans[int(1e6) + 10];
 5 
 6 inline void read(int &x) {
 7     char c = x = 0;
 8     while(!isdigit(c)) c = getchar();
 9     while(isdigit(c)) x = x * 10 + c - '0', c = getchar();
10 }
11 
12 struct Tree {
13     int ch[N][2], fa[N], root, dfn[N], pos[N], clk, vis[N];
14     Tree() { vis[0] = 1; }
15     void dfs(int u) {
16         if(ch[u][0]) dfs(ch[u][0]);
17         dfn[pos[u] = ++ clk] = u;
18         if(ch[u][1]) dfs(ch[u][1]);
19     }
20     inline int rot(int u) {
21 //        cout << "rot in " << u << endl;
22         ans[++ tot] = u;
23         int f = fa[u], g = fa[f];
24         if(g) ch[g][ch[g][1] == f] = u;
25         fa[u] = g;
26         int k = ch[f][1] == u;
27         ch[f][k] = ch[u][!k];
28         if(ch[u][!k]) fa[ch[u][!k]] = f;
29         ch[u][!k] = f, fa[f] = u;
30     }
31     inline void splay(int u) {
32 //        printf("splay: %d\n", u);
33         for(int f = fa[u] ; !vis[f] ; f = fa[u]) {
34 //            printf("fa[%d] = %d\n", u, fa[u]);
35             int g = fa[f];
36             if((ch[g][0] == f) == (ch[f][0] == u)) {
37                 if(!vis[g]) rot(f);
38             } else {
39                 rot(u);
40             }
41             if(!vis[fa[u]]) rot(u);
42         }
43 //        printf("splay end\n");
44         vis[u] = 1;
45     }
46 } xx, mz;
47 
48 void dfs(int u) {
49 //    cout << "tot = " << tot << endl;
50     if(!u) return ;
51     xx.splay(xx.dfn[mz.pos[u]]);
52     dfs(mz.ch[u][0]), dfs(mz.ch[u][1]);
53 }
54 
55 int main() {
56 //    freopen("data.in", "r", stdin);
57 //    freopen("data.out", "w", stdout);
58     freopen("become.in", "r", stdin);
59     freopen("become.out", "w", stdout);
60     read(n);
61     for(int i = 1 ; i <= n ; ++ i) {
62         read(xx.ch[i][0]), read(xx.ch[i][1]);
63         if(xx.ch[i][0]) xx.fa[xx.ch[i][0]] = i;
64         if(xx.ch[i][1]) xx.fa[xx.ch[i][1]] = i;
65     }
66     for(int i = 1 ; i <= n ; ++ i) {
67         read(mz.ch[i][0]), read(mz.ch[i][1]);
68         if(mz.ch[i][0]) mz.fa[mz.ch[i][0]] = i;
69         if(mz.ch[i][1]) mz.fa[mz.ch[i][1]] = i;
70     }
71     for(int i = 1 ; i <= n ; ++ i) {
72         if(!xx.fa[i]) xx.root = i;
73         if(!mz.fa[i]) mz.root = i;
74     }
75     xx.dfs(xx.root), mz.dfs(mz.root), dfs(mz.root), printf("%d\n", tot);
76     for(int i = 1 ; i <= tot ; ++ i) printf("%d\n", ans[i]);
77 }
NTOJ 1013 [RYOI2018ER]变成

转载于:https://www.cnblogs.com/KingSann/articles/9589037.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值