P2342 叠积木

题面君给你打招呼喽~~~

恩首先说一下非正解的一种方法,可以在洛谷上骗到9个点(共11个点,两个TLE,若吸氧则可以骗到10个点)

该方法呢也是有一定的并查集思想,但在合并上并非路径压缩或是按秩合并,而是。。怎么说呢。。顺序合并??嗯差不多。大致解释一下呢就是再合并时将下面一堆的根节点的父亲节点指向被移动的叶子节点,且将该叶子节点的子节点指向下面一堆的根节点,每次输出时从读入的a开始向下遍历,知道叶子节点停止并输出,以下为非正解代码:

 1 #include<set>
 2 #include<map>
 3 #include<list>
 4 #include<queue>
 5 #include<stack>
 6 #include<string>
 7 #include<cmath>
 8 #include<ctime>
 9 #include<vector>
10 #include<bitset>
11 #include<memory>
12 #include<utility>
13 #include<cstdio>
14 #include<sstream>
15 #include<iostream>
16 #include<cstdlib>
17 #include<cstring>
18 #include<algorithm>
19 using namespace std;
20 
21 int n,ans;
22 int z[30005],y[30005];
23 
24 int get(){//快读
25     char c=getchar();
26     int res=0;
27     while(c<'0'||c>'9'){
28         c=getchar();
29     }
30     while(c>='0'&&c<='9'){
31         res=(res<<3)+(res<<1)+c-'0';
32         c=getchar();
33     }
34     return res;
35 }
36 
37 inline int dep(int a){//求一个节点到叶子节点的深度
38     return a==y[a]?0:1+(dep(y[a]));
39 }
40 
41 inline int top(int a){//求含a节点的树的根节点
42     return a==z[a]?a:top(z[a]);
43 }
44 
45 inline int down(int a){//求含a节点的树的叶子节点
46     return a==y[a]?a:down(y[a]);
47 }
48 
49 int main(){
50     n=get();
51     for(int i=1;i<=30000;i++){//初始化
52         z[i]=y[i]=i;
53     }
54     while(n--){
55         char s;
56         cin>>s;
57         if(s=='M'){
58             int a=get(),b=get();//移动一堆积木
59             a=down(a),b=top(b);
60             z[b]=a;
61             y[a]=b;
62         }
63         else{
64             int a=get();
65             int ans=0;
66             //printf("%d\n",dep(a));//这句话跟下面两行是一样的意思,只是闲的没事干看看能不能变快一点。。
67             for(;a!=y[a];a=y[a])ans++;
68             printf("%d\n",ans);
69         }
70     }
71     //for(int i=1;i<=6;i++){//调试用
72     //    printf("%d %d %d\n",z[i],y[i],dep(i));
73     //}
74     return 0;
75 }

好的,那么这个非正解的骗分代码就写好了,但是这个代码即使吸了氧还是有一个点会超时,那么我们就需要引出正解:带权并查集

但是。。。

时候不早了,我这题正解编了好长时间还是不对。。。

so有时间再把这个坑补上吧。。。(希望我还能记得)

先睡了,晚安~~

以上写就与19.7.4 3:30

19.7.4 7:27补坑ing

好的我来补坑了,由于我们需要知道哪些积木在同一堆里,故想到用并查集,而我们又需要知道每两块积木之间的关系,以待求某块积木下有多少块积木,于是想到按秩合并或带权并查集,并记录每一堆里有多少积木,我上面的做法倒是有一点按秩合并的影子,但。。我也不知道是什么诡异的算法,可能。。还有一点链式结构的影子???好吧怪不得分拿不满嘤嘤嘤(虽然说考场上要是能打出来只错两个点的程序我基本也就心满意足了)

 1 #include<set>
 2 #include<map>
 3 #include<list>
 4 #include<queue>
 5 #include<stack>
 6 #include<string>
 7 #include<cmath>
 8 #include<ctime>
 9 #include<vector>
10 #include<bitset>
11 #include<memory>
12 #include<utility>
13 #include<cstdio>
14 #include<sstream>
15 #include<iostream>
16 #include<cstdlib>
17 #include<cstring>
18 #include<algorithm>
19 using namespace std;
20 
21 int q;
22 int f[100005],d[100005],s[100005];
23 
24 int find(int z){//查找代表元并更新高度
25     if(f[z]==z)return z;
26     int t=find(f[z]);
27     d[z]+=d[f[z]];
28     return f[z]=t;
29 }
30 
31 int main() {
32     scanf("%d",&q);
33     for(int i=1;i<=q;i++){//初始化
34         f[i]=i,d[i]=0,s[i]=1;
35     }
36     for(int i=1;i<=q;++i){
37         char zyy;
38         cin>>zyy;
39         if(zyy=='M'){//合并的情况
40             int z,y;
41             scanf("%d%d",&z,&y);
42             z=find(z);
43             y=find(y);
44             f[z]=y;
45             d[z]=s[y];
46             s[y]+=s[z];
47         }
48         else{//输出的情况
49             int zy;
50             scanf("%d",&zy);
51             find(zy);
52             printf("%d\n",d[zy]);
53         }
54     }
55     return 0;
56 }

emmmm,真棒,坑不完了,7点47了,要上课去了,白白~~~

转载于:https://www.cnblogs.com/hahaha2124652975/p/11130070.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值