Fork me on GitHub

POJ1182-食物链

继续刷邝斌飞并查集

POJ

可用平台

洛谷

这题没出好感觉,题意太bugbug了,如果样例1 2 3 5 101全是同类也有可能啊,那就是有4句假话了。懂了,题意没错,只要不是三种情况之一就是真话,(但第一句也不一定是真话)

所以题意其实就是:

只要不是自身吃自身和比N大,那么就以输入的顺序,先输入的默认为真话,然后后面输入的与前面的有矛盾,后输入的就是假话。

但样例又搞不懂了,样例只有

2 3 3
1 1 3

 

是错的,按照三角关系这句话 2 3 1 没问题,还有哪句话是错的啊。翻了洛谷3页讨论总算懂了

 

 

读完题起手思考:总共就两类:

1开头句式,2开头句式

1开头句式如果两个数(<=N)一样,或者同一个根即为真,否则假话计数器ans++。本着与前面不矛盾即为真的思想,再把这句话,俩数根弄成同一个根

2开头句式如果两个数(<=N,且没有自身吃自身),根一样,则为真,否则假话计数器ans++。本着与前面不矛盾即为真的思想,再把这俩不同的数处理下,处理方式用-1代表A,-2代表B,-3代表C,第一次加进来的真话就当成A(因为是环形,所以随便,第一个来当A就行,比如先说2 6 7,那就是6吃7,6是A,7是B),然后一次BC,判断的时候用-1,-2,-3的相反数1,2,3,找出根,我能吃你的条件就变成了:当且仅当,我比你小,且仅小1,或者我比你大,且仅大2,即1可以吃2,1不可以吃32不可以吃12可以吃33可以吃1,3不可以吃2

 

再具体点

超N和自身吃自身都会先排除,然后这里的“第一次加进来”和不是第一次加进来的,里面逻辑判断很多,是重点:

先设个状态寄存变量vis数组,memset(0),设个属性寄存变量名字就叫ABC数组,ABC[0]是-1,ABC[1]是-2,ABC[2]是-3,(代表啥不用我说了吧),遍历K句话,

当输入的第2、3个数字的vis都是0,那vis置为1,然后去检测第1个数字是几,如果为1,则将ABC弹出一个,即-1作为这俩数的pre(根),如果为2,将ABC数组弹出两个分别给这俩数

当输入的第2、3个数字的vis一个0一个1,vis都置1,然后去检测第1个数字是几,如果为1,将vis为0的那个数,根挂在vis为1的上,做同根,如果为2,弹出ABC数组的一个值给vis为0的,作为vis为0的那个数的根。(比如已经有6吃7,现在输入的是5吃6或者7吃5,新出现的是5,且6和7之前必然被赋值根为-1和-2,现在将-3给5作为根,不对,6和7也有可能为-2和-3,那其实新加的5的根就应该是-1,所以应该判断6的根,假设是5吃6(即第2个数vis是1),如果6根是-1,则相反数是1,那5赋值为3的相反数-3,如果6的根是-2,5根应该是赋值-1,如果6根是-3,5分应该是-2,假设7吃5(即第1个数vis是1),如果7根是-1,则5根赋-2,如果7根是-2,则5赋-3,如果7根是-3,则5赋-1。

当输入的第2、3个数vis都是0,看两个数根,然后去跟第一个数对比,不对就ans++

 

麻痹的好复杂,感觉有点像模拟,待会写完看看题解,之前样例不懂的时候看了很多题解,想弄懂样例,尽量肉眼屏蔽思路和做法,但还是瞟到一眼说什么带权并查集种类并查集,我写成了个模拟,先写写看

 

不对不写了,果断止损不浪费时间去写了,直接看题解学新东西,因为发现,当输入的第2、3个数字的vis都是0,那vis置为1,然后去检测第1个数字是几,如果为1,则将ABC弹出一个,即-1作为这俩数的pre(根),如果为2,将ABC数组弹出两个分别给这俩数” ,如果已经有6吃7,7吃8,8吃6,那现在告诉你1吃2且vis[1]和vis[2]都是0,这时候就可以把-1给1了么?不行,后面如果来一句,1和6同类那不就误判为错话了,因为6可以为-1-2-3任何数!!

之前有想法就写的一大好处就是通过WA到崩溃然后对拍,来提高思维缜密度,使得现在可以不用等花大把时间写完才能知道思维有漏洞,循序渐进的过程,而如果一开始不会就立马看题解,也不自己写写看,那我的代码水平连现在的一半都不如,什么都不会记住。V8不管多离谱有思路就写,q神51nod站长:想破脑袋才有提升,山理刘晓红惊蛰雨金泽宇首个金牌对我说想1h没思路就看题解
View Code

 

至此学过的知识无法解决此题了

 

不对好像还可以挣扎一下,那我如果不直接赋-1-2-3,而是先挂在对方身上呢?把对方当根,可是如果两个数都是vis为0,现在告诉你1吃2,你去看ABC数组,弹出了几个,如果一个都没弹出那好说,可如果弹出了两个,那如果之前已经有了6吃7,6根是-1,那1根也确定不了,可能为-1可能为-2可能为-3

 

惊为天人神乎其神绝世好文,持续高潮博客(后面我用到的数据例子都是这里的那个例子)堪称天龙八部顶尖武学里的小无相功(博客虽然写的相当的棒,但我理解起来还需要搭很多桥,就写一下,增加印象吧)

这代码有个地方一直没懂,

图画出来了,数据还是高潮小无相功博客里的数据,为了双击变量名后全部关联变量高亮(百度也没查到为啥最少3个字符的变量才会高亮),我索性将fa改成的faa,代码

 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 inline int read(){
 5     char c = getchar(); int n = 0;
 6     while (c < '0' || c > '9') { c = getchar(); }
 7     while (c >= '0' && c <= '9') { n = (n << 1) + (n << 3) + (c & 15); c = getchar(); }
 8     return n;
 9 }
10 #define maxN 100005
11 int n,m,ans,faa[maxN*3];
12 int find(int u)
13 {
14     return faa[u]==u?u:faa[u]=find(faa[u]);
15 }
16 
17 int main() {
18     n=read(),m=read();
19     for(int i=1;i<=n*3;i++)
20         faa[i]=i;
21     for(;m;m--) {
22         int opt=read(),u=read(),v=read();
23         if(u>n||v>n){
24             ans++;
25             continue;
26         }
27         if(opt==1){
28             if(find(u+n)==find(v)||find(u)==find(v+n))
29                 ans++;
30             else{
31                 faa[find(u)]=find(v);
32 //                cout<<"!"<<faa[find(u)]<<" "<<find(v)<<endl;
33                 faa[find(u+n)]=find(v + n);
34 //                cout<<"$"<<faa[find(u+n)]<<" "<<find(v + n)<<endl;
35                 faa[find(u+n+n)]=find(v+n+n);
36 //                cout<<"%"<<faa[find(u+n+n)]<<" "<<find(v+n+n)<<endl;
37             }
38         }
39         if(opt==2){
40             if(find(u)==find(v)||find(u)==find(v+n))
41                 ans++;
42             else{
43                 faa[find(u+n)]=find(v);
44 //                cout<<"&"<<faa[find(u+n)]<<" "<<find(v)<<endl;
45                 faa[find(u+n+n)]=find(v+n);
46 //                cout<<"^"<<faa[find(u+n+n)]<<" "<<find(v+n)<<endl;
47                 faa[find(u)]=find(v+n+n);
48 //                cout<<"@"<<faa[find(u)]<<" "<<find(v+n+n)<<endl;
49             }
50         }
51         cout<<"————"<<faa[1]<<" "<<find(1)<<endl;//再次证明faa记录的只是前面一个点,faa并不是根,用下面第二个例子
52     }
53     printf("%d\n", ans);
54     for(int i=1;i<=15;i++)
55     cout<<"#"<<i<<" "<<faa[find(i)]<<" "<<find(i)<<endl;
56 }
57 //4 4
58 //1 1 3
59 //2 2 4
60 //2 3 2
61 //2 3 4
62 
63 //4 3
64 //2 1 3
65 //2 3 4
66 //1 4 2
View Code

可以看到,我在输入第三个数据2 3 2时候,Fa3=f10=8,意思是3吃2,那图上应该3指向10(2)再指向8(4)的,(因为上一个数据输入的是2 2 4),但tmd这Fa3直接指向8(4)了,那3吃2,2吃4的关系不就没了,这tm直接成了3吃4???所以我自己出了如下几组数据:

2 3 4
2 4 3
2 2 4
2 4 2

我懂了,这个种类并查集有多种写法,高潮博客写的代码和图完美的用了两种不同写法,导致弄了一天才明白,借此透彻了解下种类并查集,掰开揉碎说下:

就比如他图里写的是B中的1找到了终结根是A中的4,他将含义解释成4吃1。

如果按照B集群的1是真正的1,然后顺序去标号,也应该是1找到了12,

如果按照A中的1是真正的1,也应该是5找到了4,

如果按照C中的1,也应该是,9找到了8,

而他代码里,即我图里画的,A中的1找到了B中的8,B中5找到C中12,C中9找到A中4

且他代码里写的,即当有A中的点的终极上级,即根,是在B中,那么这条路其实是B中的那个点被A中的那个点吃,自己画画就可以理解

即AB是一个反的,简述就是,代码写的是,B吃A,A吃C,C吃B。再多解释一下就是,如果C中某点x的根,在B中为y,则x吃y,而B中某点x的根,在C中为y,则是y吃x。

差别在于,瞅我画的内个图,看2 3 2那条数据,7(3)是直接指向了12(4),本身应该是7(3)指向2的,但已经有了2指向12(4),捋顺一下,至此,有2指向12(4),又来了新数据说3指向2,那我为了压缩路径,我只想7(3)指2的根12,又由于有三角关系,得知12(4)吃7(3),那我就7(3)指向12(4)然后规定B里的指向C里的就反着的

  

至此想到几个事:

想法1、我直接正着存行不行,别B集群去C集群的点还是被吃关系(他写的代码本身2吃4,应该是2吃8,他tm写成了2吃12,能A吃B非得搞成A吃C)

想法2、我直接不压缩路径,那所有关系不就都在图里了吗?就博客里的图那样,(因为你这直接把过度给整没了实在不好理解啊,我就想7(3)指向2再指12(4))

(这样思考有助于提高思维缜密性和逻辑,所有想法都试过一遍哪个对哪个错,心里有数,不至于以后变个型就不会了)

另外他的数组大小也开错了,N个点,N是50000,3*N即可,他是按照K的值去开的,没必要

首先我想了下,想法2,根本没法写,原因见下面代码37行,主要还是同种物种类引发的,下面的代码注释相当棒,看的顺序是,我先改动的 if(opt==2) 里的,然后是 if(opt==1) 这里的,故得出结论只能像博主那样,压缩路径

 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 inline int read(){
 5     char c = getchar(); int n = 0;
 6     while (c < '0' || c > '9') { c = getchar(); }
 7     while (c >= '0' && c <= '9') { n = (n << 1) + (n << 3) + (c & 15); c = getchar(); }
 8     return n;
 9 }
10 #define maxN 50001
11 int n,m,ans,faa[maxN*3];
12 int find(int u)
13 {
14     if(faa[u]==u)
15         return u;
16     return find(faa[u]);//不压缩路径faa存的只是前驱,仅仅是前面一个
17 }
18 int main(){
19     n=read(),m=read();
20     for(int i=1;i<=n*3;i++)
21         faa[i]=i;
22     for(;m;m--) {
23         int opt=read(),u=read(),v=read();
24         if(u>n||v>n){
25             ans++;
26             continue;
27         }
28         if(opt==1){//找同类的代码没法用想法2
29 //            if(find(u)==find(v+n)||find(v)==find(u+n))//左表达式v吃u,右表达式u吃v,因为他代码逻辑是B里的是A里的
30 //                ans++;//这两句是博主原写法
31 
32 //            if(faa[u]==v+n+n || faa[v]==u+n+n)//左表达式我吃你的地方可以用想法2,如果u吃v。右表达式如果v吃u
33 //                ans++;
34 ////当然按照想法2的写法,我不压缩路径(洛谷博主Sooke压缩路径的写法,所有压缩路径都是,faa记录的只是前驱,每次else里的赋值便可以看出来,只不过,听好了啊!!,只不过每次找某个点的根的时候,即find函数会顺便给你路径压缩了)来写,那还需要判断最后一个种类倒吃我的情况,当然代码主风格还是按照博主代码的思路。B吃A,A吃C,C吃B,但这种我被尾巴吃的情况不一定会表现出来,比如博主的例子,3吃2,2吃4,那默认4吃3,所以不能再用普通的faa来判断了,这几行注释掉,见下行
35 
36 //注意下一行我加的是我被尾巴吃的情况,但再记住,如果种类多了,则没法写了
37             if(faa[u]==v+n+n || faa[v]==u+n+n || faa[u])//不对,2个种类也没法写,因为还是同类问题引发的,u是1,我写的faa[u],则是3,但我其实想要的u是3,即出了本集群的
38                 ans++;
39             else{//同类不动
40                 faa[find(u)]=find(v);//这几个都不能动,因为可能是两串数字拼接,如果123456六个数123同类都指向了3,456同类都指向了6,又给你句14同类,那你不得一直找根去挂
41                 faa[find(u+n)]=find(v + n);
42                 faa[find(u+n+n)]=find(v+n+n);
43             }
44         }
45         if(opt==2){
46 //            if(find(u)==find(v)||find(u)==find(v+n))//左表达式uv同类,右表表达式v吃u,换一种写法依旧AC,见下句。其实很好理解,u是A集群里的n+v是B集群里的,他俩有关系,则是B吃A
47 //            if(find(u)==find(v)||find(v)==find(u+n+n))//A和C里的有关,是A吃C。依旧AC。再换种写法
48 //                ans++;
49             if(faa[u]==v+n+n || find(u)==find(v)) //右表达式只要涉及找同类没法用想法2,(因为同类可以有很多123456都是同类那12345的最根部都是6,只找前驱可不行)而且想法2的写法不精简,也感觉没法代入其他题目,不是通解,种类变了感觉都又得重想
50                 ans++;
51             else{
52                 faa[u+n]=v//而我吃你,就单纯的我吃你,不存在什么我跟你的前驱有什么关系,只有在,比如总共n个种类,那我吃了你,你吃了他,他吃其他,经过n次顺序吃的时候,才会有n那个种类吃我的问题。
53                 faa[u+n+n]=v+n;
54                 faa[u]=v+n+n;
55             }
56         }
57     }
58     printf("%d\n", ans);
59 }
60 //4 4
61 //1 1 3
62 //2 2 4
63 //2 3 2
64 //2 3 4
65 
66 //4 3
67 //2 1 3
68 //2 3 4
69 //1 4 2
70 
71 //4 3
72 //1 1 3
73 //2 2 4
74 //2 3 2
View Code

 

 

再记录下压缩路径与不压缩路径的差别(原Sooke博主加了快读,故所有测试都有快读):

可用平台:(限制:1s、64M)

原博主代码14ms、848K

去掉压缩路径12ms、848K

POJ:(时限1s、10M)

原博主代码47ms、944K

去掉压缩路径47ms、944K

洛谷:(时限1s、125M)

原博主代码58ms、1012K

去掉压缩路径59ms、1012K

这人压缩路径写的没问题,不像上个博客那人写了个假的压缩路径,这题一个点出发最多有两个指向,即A指了B,B指了C,顶多也就两层,压了是一层,差别不大

 

 

POJ讨论区说cin会TLE,输入多组会WA(有可能原因),我用博主代码试下

cin只有POJ会TLE,其他俩平台都AC

输入多组数据居然所有平台都WA了,

下载了洛谷数据,妈的数据太长只能上传文件,或者可以朝我要洛谷账号,自己去下载测试数据

文件里是洛谷的第九个测试数据,正确输出是71。注意控制台输入不了,用 freopen 读入,我将这个文件测试数据单独输入输出71,但把题目样例放在前面就会输出

3
71
43009

利用codeblock行数统计,发现确实如上面“有可能原因”里说的,这个测试数据后面不止有65535行

但为啥少一行,假话变多了?理应从2行到65536是输入数据71句假话,但我不小心只复制到了65535,却72句假话,而又少一行又多一句假话,而我造了个数据试了试,

100 8
1 101 1 
2 1 2

发现将这组数据输入到控制台的时候,结果是:一直等待输入。而 freopen 却输出了7,

妈的我发现可能之前博客说过的跟内存分配有关?比如你现在电脑哪块内存空着就分配,感觉不对啊,但并不是所有少数据的用 freopen都会有输出。

惊了!!我出去吃个晚饭的功夫,回来上面那组数据就不输出7,输出1了。而且我文件那个数据前面加上题目样例输出居然变了(之前输出的43009显然不对啊,因为后面多出来的顶多80行,每次假话+1,怎么会有超过80个的假话呢)

3
71
70

文件中的数据我少一行发现也输出71了 ———— 妈的我重启电脑都没变化,相当之离奇!!!

得了不管为啥吃饭前那个输出8和43009了,研究下现有的数据吧,复制到codeblock研究,发现65537行的 1 43009 43393 即下一组数据即输出70的那个n和m,分别为1和43009,总共就1个点,那我大概弄懂了,接下来几行是

43393 1 43777
44161 1 44545
44929 1 45313

直接超过N,直接ans++了

我把while里换成 while(scanf("%d%d",&n,&m)) 数据用

100 7
1 101 1
2 1 2
2 2 3
2 3 3
1 1 3
2 3 1

发现自己输入控制台的时候会等待输入,而 freopen 就会循环输出一行0 —— 相当匪夷所思,搁置不管了

 

到家发现又有些想法,做下测试,关于输入:(C++真的好头疼啊,终于理解BUPT那些考研时候出的一些C语言基础语法题了,记得19考研出了个printf的题也是之前一直没在意过,LXT问我的,我还特意写了个博客,C细节坑真多)—— 持续更新

1、发现 while(cin>>n){ m=read(); ctrl+Z和C都可以结束

2、但我输入 while(n=read()){ m=read(); 的时候,如果 read() 函数里没有 if(c==EOF)return 0; 怎么都不会结束,但是有这句

 1 #include<cstdio>
 2 #include<iostream>
 3 using namespace std;
 4 inline int read(){
 5     char c = getchar(); int n = 0;
 6     if(c==EOF) return 0;
 7     while (c < '0' || c > '9')
 8         c = getchar();
 9     while(c >= '0' && c <= '9'){
10         n = (n << 1) + (n << 3) + (c & 15);
11         c = getchar();
12     }
13     return n;
14 }
15 #define maxN 100005
16 int n,m,ans,faa[maxN*3];
17 int find(int u)
18 {
19     return faa[u]==u?u:faa[u]=find(faa[u]);
20 }
21 int main(){
22     while(n=read()){
23         m=read();
24     for(int i=1;i<=n*3;i++)
25         faa[i]=i;
26     for(;m;m--) {
27         int opt=read(),u=read(),v=read();
28         if(u>n||v>n){
29             ans++;
30             continue;
31         }
32         if(opt==1){
33             if(find(u+n)==find(v)||find(u)==find(v+n))
34                 ans++;
35             else{
36                 faa[find(u)]=find(v);
37 //                cout<<"!"<<faa[find(u)]<<" "<<find(v)<<endl;
38                 faa[find(u+n)]=find(v + n);
39 //                cout<<"$"<<faa[find(u+n)]<<" "<<find(v + n)<<endl;
40                 faa[find(u+n+n)]=find(v+n+n);
41 //                cout<<"%"<<faa[find(u+n+n)]<<" "<<find(v+n+n)<<endl;
42             }
43         }
44         if(opt==2){
45             if(find(u)==find(v)||find(u)==find(v+n))
46                 ans++;
47             else{
48                 faa[find(u+n)]=find(v);
49 //                cout<<"&"<<faa[find(u+n)]<<" "<<find(v)<<endl;
50                 faa[find(u+n+n)]=find(v+n);
51 //                cout<<"^"<<faa[find(u+n+n)]<<" "<<find(v+n)<<endl;
52                 faa[find(u)]=find(v+n+n);
53 //                cout<<"@"<<faa[find(u)]<<" "<<find(v+n+n)<<endl;
54             }
55         }
56 //        cout<<"————"<<faa[1]<<" "<<find(1)<<endl;//再次证明faa记录的只是前面一个点,faa并不是根,用下面第二个例子
57     }
58     printf("%d\n", ans);
59 //    for(int i=1;i<=15;i++)
60 //    cout<<"#"<<i<<" "<<faa[find(i)]<<" "<<find(i)<<endl;
61 }
62 }
63 //4 4
64 //1 1 3
65 //2 2 4
66 //2 3 2
67 //2 3 4
68 
69 //4 3
70 //2 1 3
71 //2 3 4
72 //1 4 2
73 
74 //100 7
75 //1 101 1 
76 //2 1 2
77 //2 2 3 
78 //2 3 3 
79 //1 1 3 
80 //2 3 1 
81 //1 5 5
View Code

,也不是输入完一组数据就结束,而是需要再输入3个数,然后有三个输出,才会结束。

3、题目样例,代码输入如果是 while(n=read()!=EOF){ m=read(); 那 read 函数里无论有没有EOFreturn0,都输出7,且怎么都不会结束

4、输入里去掉EOF会正常输出3,但freopen不结束了,必须txt读入文件里去掉最后的回车才会结束

5、输入里去掉EOF,用freopen,且输入是

100 7
1 101 1
2 1 2

发现每次都有输入数据,输出1,并不会等待你输入

6、read需要读入两个的时候 while 怎么写

7、之前多组数据没在意,现在发现的问题,去反推之前AC的代码(数字快读和字母快读),如果多组数据输入不足是否会也能有输出

第二天来图书馆,问了下百度文心AI技术大牛GPT(之前挺鄙视百度和百度的gpt的实际用起来发现也挺牛逼,还是不要人云亦云),我!滴!妈!快读里居然这么多学问,归根到底还是 while  return -1 or 0  EOF  getchar 这些问题,基础太弱了,之前用快读都是直接套模板,从没有想过这里居然有坑,没去好好理解这些东西

 

---------------------先叙述下刚学到的关于一些输入的基础知识:(百度文心牛逼!)-----------------------

——1、首先展示这样一段代码(这段相当重要精华)—— 注意这段代码ctrlZ不会结束,至于原因,我写这段话的时候也不知道,还在研究,但肯定会研究出来,后面说

 1 #include <iostream>
 2 using namespace std;
 3 inline int read(){
 4     char c = getchar();
 5     int n = 0;
 6     while (c < '0' || c > '9'){
 7         c = getchar();
 8     }
 9     while (c >= '0' && c <= '9'){//这俩位置呼唤居然也有问题
10         n = (n << 1) + (n << 3) + (c & 15);
11         c = getchar();
12     }
13     return n;
14 }
15 int main() {
16     int n, m;
17     while(n = read()){//输入0结束
18         cout << n << endl;
19     }
20     return 0;
21 }
View Code

你输入9,敲回车,程序在 read() 函数里先4行那读入了9这个字符,第一个 while 不进,进第二个while,这个运算表示的是乘2+乘8,即乘10,然后看 c&15那,这里c是一个字符,想把它当作数字来处理,通过与15(即二进制1111)进行按位与操作,可以得到c字符对应的ASCII码值中的低4位。因为ASCII码中,数字0到9的二进制表示分别是00110000到 00111001,0的ASC码是48,所以这一步实际上是提取出了c字符所代表的数字(0到9),那我再输入回车,回车的ASC码是13,空格的ASC是32, while 就跳出了,去 return ,到了 main函数 里4不是0就输出了。所以这里你如果输入0,程序就会结束。

而且还有一点有趣的,我编程这么久头一次见到 while 或者 for 的顺序会影响结果的,这里如果将read()函数里的两个while互换,第一个while相当于清道夫它确保了在开始读取数字之前,输入流中没有任何会干扰数字读取的字符,第二个while则是负责读取数字字符并把它们组合成一个整数,它只有在确认输入流中接下来是数字字符时才会开始工作,遇到第一个非数字的就结束,然后return输入过的数字。

如果互换产生两个错误,

其一:输入“a8”本应该输出8,却会由于输入a导致先进去第二个while,即交换前的第一个while,即代码里6~8行那段,然后输入8不符合跳出,即程序会直接结束什么也不输出。

其二:输入6敲回车,再输入9敲回车,再输入4敲回车,本应该在输入6敲回车后就立马输出6,输入9敲回车后立马输出9,输入4敲回车立马输出4,结果却是,输入6敲回车,啥也不输出,因为输入6程序先进入第一个while即代码里9行那段(注意我说交换两个while),敲回车则跳出进入第二个while(原代码6行那段),这个回车会被丢弃,再输入,输的是9,然后回车,发现9不符合,跳出,此时输出的是前面第一次输入的6,注意9后的回车还在缓存里,(其实你只需要在 while (c < '0' || c > '9'){ 下加一个  cout<<"#"<<n<<endl; 就显而易见了)这时候再输入4,再敲回车,注意了此时缓存里是:回车、4、回车,程序直接来到代码里的6行那里,然后输入的4不符合就跳出了(此时n是0),继续return了,然后返回main了,但重点来了,跳出后return携带的n是几?注意我输出6后程序带着缓存里的:回车、4、回车,这仨数据,重新进入了read()函数,即n重新int为0了,所以n是0,所以return携带着0返回给了main,那程序直接就结束了

CNM小小快读这么多逼事呢,浪费老子大半天时间

另外,输入 asd6 r8t 敲回车,输出6和8,好理解

输入789,敲回车,输出789,都好理解

——2、再看这样一段代码(为了方便简称叫TWO代码)(备注:我刚发现多个#头文件都放到一行只读取首个#头文件,必须一个头文件一行)

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<iostream>
 4 using namespace std;
 5 int n;
 6 int m;
 7 inline int read() {
 8     char c = getchar(); int n = 0;
 9     if(c==EOF)return 0;
10     while (c < '0' || c > '9') { c = getchar(); }
11     while (c >= '0' && c <= '9') { n = (n << 1) + (n << 3) + (c & 15); c = getchar(); }
12     return n;
13 }
14 int main()
15 {
16     while(n=read()){
17             cin>>m;
18         cout<<n<<endl;
19     }
20 
21 }
View Code

这段代码输入4 5后输出4,再输入Ctrl+Z就return 0了,返回的n就是0,为什么main里的while还会执行,还不结束程序呢?

我TM之前AC代码都是这么写的貌似,居然AC了,细思极恐

可是去掉  cin >> m; Ctrl+Z就可以结束

而且离奇的是将那个EOF判断换一下,

 1 #include<stdio.h>
 2 #include <iostream>
 3 using namespace std;
 4 inline int read() {
 5     char c = getchar(); int n = 0;
 6     while (c < '0' || c > '9'){
 7         if(c==EOF)
 8             return 0;
 9         c = getchar();
10     }
11     while (c >= '0' && c <= '9'){
12         n = (n << 1) + (n << 3) + (c & 15);
13         c = getchar();
14     }
15     return n;
16 }
17 
18 
19 int main(){
20     int n, m;
21     while(n = read()){
22         cin >> m;
23         cout << n << endl;
24     }
25 }
View Code

居然可以输入4 5后输出4,再输入Ctrl+Z就结束程序

这个问题百度文心GPT始终没给我解释清楚

 

→(插入,科普几个东西

科普①:char是char类型,表示一个字符。char类型通常是有符号或无符号的8位整数

科普②:getchar是C++标准库中的一个函数,它的作用是从标准输入(通常是键盘)读取下一个可用的字符,并返回它。不过要注意,getchar返回的值是int类型的,而不是char类型。这是因为getchar需要返回一个特殊的值EOF(通常是-1)来表示已经到达文件末尾或发生了读取错误。而对于32位整型(int),-1的二进制表示是32个1,即11111111 11111111 11111111 11111111,即32位,超出了char类型的表示范围,所以EOF不能表示为char类型的值),所以getchar返回int类型

1     char str=49;
2     cout<<str<<endl;//输出1
3     char str1=getchar();
4     cout<<"______"<<str1<<endl;
5     char str='a';//输出a  字符是a,值是97
6     char str1=97;//输出a
7     cout<<str<<" "<<str1<<endl;
View Code

科普③:Ctrl+Z和-1都没有ASC值。char8位总共255,但asc只能表示到127,剩下的那128个值(从128到255)在扩展ASC里

科普④:getchar每次只会读取一个字符,遇到空格回车也会吸收当作下一次的getchar读取字符,一般我叫他“吃回车”。科普结束)←

 

但当我将上面的TWO的代码加几个输出(简称TWO加输出

 1 #include<stdio.h>
 2 #include <iostream>
 3 using namespace std;
 4 inline int read() {
 5     char c = getchar(); int n = 0;
 6     if(c==EOF)
 7         return 0;
 8     cout<<"!"<<c<<"^"<<endl;
 9     while (c < '0' || c > '9'){
10         cout<<"#"<<endl;
11         c = getchar();
12     }
13     while (c >= '0' && c <= '9'){
14         cout<<"@"<<endl;
15         n = (n << 1) + (n << 3) + (c & 15);
16         c = getchar();
17     }
18     return n;
19 }
20 int main(){
21     int n, m;
22     while(n = read()){
23         cin >> m;
24         cout << n << endl;
25     }
26 }
View Code

终于发现问题了,Ctrl+C和Z的ASC好像都被判断为了 c < '0' 即你运行TWO代码,输入4 5敲回车,输出4,没毛病,但再输入Ctrl+Z就会一直等待你输入东西,而运行加输出的这个代码,在输入Ctrl+Z后会输出“#”,发现他进入了 while (c < '0' || c > '9') 这个判断

那我就懂了,用这个加了几个输出的代码来说一下上面的疑惑TWO代码(GPT始终没解释清楚一直说:“这是下一次的迭代” 和 “始终不会执行return 0”)。

其实当你输入4 5后,敲回车,会输出 !4^ ,此时缓存里有回车,

然后read()函数里回车被c读了,EOF那个判断并不会生效,然后输出语句 cout<<"!"<<c<<"^"<<endl; 实际控制台输出的是 !和 ^ 之间有个回车,也验证了这一点,此时进入while<'0'那,输出“#’,好了至此是输入4 5后的控制台上的展示结果

接下来你本意是想结束,于是输入了Ctrl+Z敲了回车,这时候缓存里是:Ctrl+Z和回车这俩玩意,注意现在程序在while<'0'那,把CtrlZ的ASC当成了<'0'(事实就是这样,尽管不符合前面老子查到的“CtrlZ没有ASC”这一规则),所以还在这while里,输出了“#”。

但注意此时又学到一个关于getchar的细节,你缓存里有Ctrl+Z和回车这俩玩意,输出的“#’”是关于CtrlZ的,即他的ASC<'0',但缓存里还有回车,所以不是一次输出俩“#”,引用文心GPT

这个问题挺有意思的!在C++中,getchar 函数的行为确实与输入缓冲区(缓存)中的内容有关。

具体来说,当输入缓冲区中有未处理的字符时,getchar 会读取并返回缓冲区中的下一个字符。它不会一次性“全部输出”缓冲区中的内容,而是每次调用时读取一个字符。

举个例子,如果你在之前已经输入了一些字符并按下了回车键,但这些字符还没有被任何读取函数(如 getchar)处理过,那么当你调用 getchar 时,它会依次读取并返回这些字符,直到缓冲区为空或者遇到了文件结束符(EOF)。

需要注意的是,输入缓冲区通常是由操作系统管理的,它会在用户按下回车键或者输入缓冲区满时自动刷新到程序中。因此,在某些情况下,你可能需要多次调用 getchar 才能读取完用户输入的所有字符。
View Code

所以return 0永远不会执行,那么将他放到while<'0'里即可 —— 致敬文心GPT,牛逼!!!

诶!!等会,不对不对,上面说的不对,我重新试了下,当你输入4 5敲回车,再输入Ctrl+Z敲回车的时候,注意此时缓存里是Ctrl+Z和回车,虽然输出了“#”,我误以为是Ctrl当作了<'0',但当你再输入6敲回车发现输出了“@”,是等待你输入m的意思,我又懂了,捋顺一下,缓存里是Ctrl+Z和回车,此时如果输出的“#”是因为Ctrl+Z,那缓存里会有回车,你再输入6敲回车,此时缓存里是:回车1、6、回车2这仨玩意,应该输出“#”,但却输出了“@”,证明Ctrl+Z那个输入根本没处理,输出“#”是因为处理的是回车1,所以当输入6敲回车,才会输出“@”

——2.1、 while(n = read()!=-1) 这段代码有问题,比较运算符(如==!=<>等)的优先级是高于赋值运算符(=)的。直接每次输入无论啥数,n都是1

——2.2、  while(n = read() && cin >> m) 这句话也有问题,赋值运算符(=)的优先级是高于逻辑与运算符(&&)的,即先执行read()函数调用,并将返回值赋给n,然后才会判断n是否非零,如果非零再执行cin >> m。但是,要注意!赋值运算符的优先级虽然高,但它是一个右结合运算符,这意味着它会从右向左进行运算。

即n永远是1

(当然,逻辑与运算符&&是一个短路运算符,即假设cin >> m是一个有效的表达式,如果read()返回0,那么cin也不会执行)

——3、这段代码在控制台最开始输入Ctrl+Z/C是可以结束的,但想在输入数据后想结束,需要把判断EOFreturn 0放在 while (c < '0' || c > '9'){ 下是,且只能是Ctrl+Z,而Ctrl+C根本输入不进控制台里,只有在最初(不输入数据之前)才能输入进去,文心GPT给出的答复

这个问题挺有意思的!首先,我们要明白getchar()函数是做什么用的。getchar()函数是一个标准输入函数,它从标准输入(通常是键盘)读取下一个可用的字符,并返回它。

但是,Ctrl+C并不是一个普通的字符输入。在大多数操作系统中,Ctrl+C被用作一个中断信号(通常是SIGINT),用于终止当前正在运行的程序。当你按下Ctrl+C时,操作系统会捕获这个信号,并发送给当前正在运行的前台进程(也就是你的C++程序)。

由于Ctrl+C是一个信号,而不是一个字符,所以getchar()函数不会读取它作为输入。相反,当你的程序接收到SIGINT信号时,它通常会立即终止运行,而不会有机会去读取或处理这个信号作为输入。

因此,你的这段代码不会读入Ctrl+C,因为它根本就不是一个可以被getchar()函数读取的字符输入。相反,它是一个用于终止程序的信号。
View Code

且文心GPT昨天答的和今天答的相悖,

昨天回答的↑ 

今天回答的↑

今天回答的↑

不管了 

----------------------至此“先叙述下刚学到的关于一些输入的基础知识”结束--------------------------------

 

现在去回头看“到家发现又有些想法,做下测试,关于输入”那几个问题,

1、已解决。

2、真tm邪门!今天复现发现Ctrl+Z又能结束了,???,我EOFreturn0的判断还在while外面呢啊,对此我问GPT,“cin会读回车吗?”,GPT给出的答复如下

这个问题挺有意思的!cin在C++中读取输入时,确实会涉及到回车符的处理。不过,它的行为可能会因为不同的操作系统和终端设置而有所差异。

一般来说,当你使用cin读取字符串(比如std::string类型)时,回车符(也就是你按下回车键时产生的字符)通常会被包含在读取的字符串中。但是,这个回车符并不会被显示在字符串的内容里,它更多地是作为一个结束符,告诉cin输入已经结束了。

然而,当你使用cin读取数字(比如int、float等类型)时,情况就有所不同了。在这种情况下,回车符通常不会被读取为输入的一部分。相反,它会被视为一个输入结束的标志,告诉cin你已经完成了数字的输入。

当然啦,这些行为可能会受到你所使用的操作系统和终端设置的影响。所以,在不同的环境下,cin处理回车符的方式可能会有所不同。
View Code

“那这回车是被丢弃还是存到缓存中”,GPT给出的答复如下

这个问题问得好!在C++中,当你使用cin读取输入时,回车符的处理方式确实是一个比较微妙的问题。

一般来说,当你输入完数据并按下回车键时,这个回车符会作为输入结束的标志被cin识别。在大多数情况下,这个回车符并不会被存储在cin的缓存中,而是被用来通知cin:“嘿,我已经输入完了,你可以开始处理这些数据了!”

但是,这里有一个需要注意的地方。如果你在输入完数据并按下回车键后,没有立即进行下一次输入操作,那么这个回车符可能会被留在输入缓冲区中。等到你下一次使用cin进行输入操作时,这个回车符可能会被当作下一次输入的起始字符来处理。这可能会导致一些意想不到的行为,比如你的程序可能会跳过下一次的输入提示,直接执行后续的代码。

当然啦,这些行为也可能会受到你所使用的操作系统和终端设置的影响。在不同的环境下,cin处理回车符的方式可能会有所不同。

总的来说,虽然回车符在cin处理过程中可能会有些微妙,但只要你理解了它的行为模式,就可以避免一些常见的陷阱。希望这个解释能帮到你!如果你还有其他C++相关的问题,随时都可以问我哦
View Code

上面TWO加输出那块确实验证了,回车确实在输入4 5的5后敲回车的时候,把回车放到缓存中了。

→(我突发奇想,再试个东西

单纯cin>>n再cout,Ctrl+Z/C都是0,惊了,我一直以为CtrlCZ都是程序直接结束,现在发现如果后面有语句还会继续执行,有点像break,只不过break跳过的是循环,这个跳过的是这个语句,GPT的解释

 1 这个问题挺有意思的!在C++中,当你使用cin来读取输入时,如果按下Ctrl+Z(在Windows系统中),这通常会被解释为文件结束符(EOF)的信号。
 2 
 3 当cin接收到这个EOF信号时,它会停止继续读取输入,并设置相应的状态标志,比如failbit或eofbit。这意味着,如果你之后尝试从cin中读取数据,而没有先检查它的状态,那么你可能会得到一个读取失败的结果,或者读取到之前留在输入缓冲区中的数据(如果有的话)。
 4 
 5 现在,让我们来看看你的情况:cin >> n; cout << n;。当你按下Ctrl+Z时,cin接收到了EOF信号并停止了读取。但是,由于你没有检查cin的状态,n变量可能还没有被成功赋值(或者它可能被赋值为一个未定义的值,这取决于具体的实现和编译器)。然而,在你的例子中,输出却是0。这可能是因为你的编译器或环境在遇到EOF时,对未初始化的变量n进行了一些默认的处理,或者n之前已经被初始化为0了(尽管这在你的代码片段中并没有明确显示出来)。
 6 
 7 不过,需要注意的是,这种行为可能会受到你所使用的编译器、操作系统和终端设置的影响。在不同的环境下,cin和cout处理EOF信号的方式可能会有所不同。
 8 
 9 为了避免这种不确定性,你可以在使用cin读取数据之前和之后,检查它的状态。比如:
10 
11 cpp
12 int n;
13 cin >> n;
14 if (cin.fail()) {
15     // 处理读取失败的情况
16     cout << "读取失败!" << endl;
17     n = 0; // 或者你可以设置一个默认值
18 }
19 cout << n << endl;
20 这样,你就可以更准确地控制程序的行为,并避免因为EOF信号而导致的不确定结果了。希望这个解释能帮到你!如果你还有其他C++相关的问题,随时都可以问我哦!
View Code

 

再看下面

 1 #include<stdio.h>
 2 #include <iostream>
 3 using namespace std;
 4 inline int read() {
 5     char c = getchar(); int n = 0;
 6     if(c==EOF)
 7         return 0;
 8     cout<<"!"<<c<<"^"<<endl;
 9     while (c < '0' || c > '9'){
10         cout<<"#"<<endl;
11         c = getchar();
12     }
13     while (c >= '0' && c <= '9'){
14         cout<<"@"<<endl;
15         n = (n << 1) + (n << 3) + (c & 15);
16         c = getchar();
17     }
18     return n;
19 }
20 int main(){
21     int n, m;
22     while(n = read()){
23         cin >> m;
24         cout<<"$"<<m<<endl;
25         cout << n << endl;
26     }
27 }
View Code

这段代码你输入“456”,输出

!4^
@
@
@

没毛病,然后你输入Ctrl+Z/C都会输出

$16
456

这个16始终不知道哪里来的,但肯定是m的值了。可是输入CtrlZ缓存中啥也没有了为啥不退出??匪夷所思!!!GPT也没说清,搁置不再浪费时间了。但再输入一个Ctrl+Z程序就结束了,可见TWO加输出代码里,cin读取m的时候,回车留在了缓存里,作为下次getchar。但这里Ctrl+Z和回车都在cin读取m的时候吃掉了,没缓存了。

实验结束)← 离谱!!

但关于Ctrl+Z后还需要输入点东西才能结束,我放个图

不解释,之前解释的够多了,这个唯独“$5”那我没懂为啥,同样是缓存里有:Ctrl+Z和回车,m应该是这俩数中的某个,结果却是5,不研究了

3、已解决,——2.1说过了,比较优先级高于赋值优先级,n恒为1,输入所有都大于1,都为假,所以每次ans都会++。而n恒为1,所以EOF也永远不会结束

4、对于样例,如果用 while(n=read()){ m=read(); ,那样例只能到1 5 5结束,程序才会结束,而如果1 5 5后面有回车,则程序会一直等待你输入。这个强加解释自圆其说姑且当作freopen读取的时候,如果什么都没有就直接结束了

5、当有回车的时候会等你输入,而没回车,就会opt、u、v都为0。至于为啥GPT也没说清,搁置

6、先科普个东西

——之前说过,逗号只会判断最后一个,即 for(int i=0;1<2,i<10;i++) cout<<"!"<<endl; 输出10个,而调换约束条件里俩语句位置,会无限循环。

——while也是如此, while(1<0, 3>2) cout<<"!"<<endl; 这个语句会无效循环

—— while(n=read()&&m=read()) 这种写法有问题,先说下左右值:5是一个常量,右值,不可以进行赋值,if(5=5)写法是错误的,GPT回答:

左值(lvalue)和右值(rvalue)是C++编程语言中的两个重要概念。简单来说,左值是可以出现在赋值语句左边的表达式,而右值则不能。

让我们通过一个简单的例子来说明它们的区别:

cpp
int a = 5; // 这里,a 是一个左值,因为它可以出现在赋值语句的左边,并且它有一个可以定位的内存地址。
int b = a; // 在这里,a 仍然是一个左值,因为它被用作赋值语句的源操作数(即被赋值的对象)。
5 = a;     // 这个语句是错误的,因为 5 是一个右值,它不能出现在赋值语句的左边。
在上面的例子中,a 是一个左值,因为它代表了一个可以定位到内存地址的变量。而 5 是一个右值,因为它是一个常量,没有对应的内存地址可以修改。因此,尝试将 a 的值赋给 5 是不合法的,因为右值不能被赋值。

为什么左值可以被赋值而右值不能呢?这是因为左值通常对应着内存中的一个位置,我们可以通过这个位置来存储和修改数据。而右值则通常是一个临时的、不可修改的值,比如常量或函数的返回值。

在C++中,哪些类型的表达式通常被视为左值或右值呢?

变量(如上面的 a)通常是左值。
常量(如 5)通常是右值。
函数的返回值通常是右值(除非返回的是引用类型)。
表达式的结果(如 a + b)通常是右值,除非它们被存储在一个变量中并作为左值使用。
希望这个解释能帮到你!如果你还有其他C++相关的问题,随时都可以问我哦!
View Code

所以读取两个不可以直接那么写,GPT回答

你写的这个while(n=read()&&m=read())表达式啊,在C++里可是不合法的哦!这里面有几个问题得说说。

首先啊,赋值运算符=的优先级是低于逻辑运算符&&的。这意味着你的表达式会先计算read()&&read(),得到的结果是一个布尔值,然后再把这个布尔值赋值给n。这样一来,m就根本不会被赋值啦!

再者啊,这种写法还违反了左值的要求。赋值运算符的左侧必须是一个左值,也就是可以定位到内存地址的变量。但在你的表达式里,read()&&read()的结果是一个右值,也就是一个临时的、不可修改的值,这怎么能行呢?
View Code

所以read俩数,最好&&, while((n=read())&&(m=read())) 

7、

发现之前从最短路最后一题话剧往返,和无线网络(这里的字符快读一直就没法用,挺好,省着研究为啥AC了),开始用的快读,既然上面的2、又能结束了就不去研究了,下次用快读就写个最正确的吧,EOFreturn0放在while里

 

至此零零碎碎的问题花了我2天时间(前天晚上懂了种类并查集后开始研究这些零碎EOF问题,昨天一整天,今天大半天),都处理完毕

至此完全理解,了解了种类并查集的思想,自己再写一遍,注意不是默写!!不可以想他代码的写法,原因之前博客说好多次了

这次我用ABC正着的顺序,即博主图解的顺序来写,即想法1 

 

思路:(我是结合高潮博客的图思考的)

顺时针ABC集群
我正着存储,A集群吃B集群,B吃C集群,C吃A集群

如果A集群中的点的find根和C集群中点的find根一样(感觉不用根

即find(u)==find(v+N+N),说明Au指向了Cv,但我正着设计,即A吃B吃C吃A,你A指我C,我就规定叫C里点v吃A里点u,尽管程序上表现仅仅是A指向C而已,但有无可能C又指向了B集群我都是正着设计的,你A不去指向B来指我C,唯一的可能就是你指B(即吃B),B指C(即吃C),在压缩路径的时候,你A直接指向了我C,那根据题意我就规定跨越一个集群的叫做被反吃。那我都C吃A了,咋可能C吃B(其实解释的不对),应该说我是正着设计的,C出发的只可能指向A即吃A,比如3吃2,11(3+4+4)指向2,即find(u+N+N)==find(v)(在想find(v)还是v,发现还得要根,如果3吃2,2和3同类,那就完了),但有无可能A又指向了B集群?即根都在B集群里,有可能。

 

写了个代码WA了

 1 #include<stdio.h>
 2 #include<string.h>
 3 #define MAX 50001
 4 #include<iostream>
 5 using namespace std;
 6 int N,K;
 7 int ans;
 8 int pre[MAX*3];
 9 int find(int x)//找根
10 {
11     if(x==pre[x])
12         return x;
13     pre[x]=find(pre[x]);
14     return pre[x];
15 }
16 inline int read(){
17     char c=getchar(); int n=0;
18     while(c<'0'||c>'9'){
19         if(c==EOF)
20             return 0;
21         c = getchar();
22     }
23     while(c>='0'&&c<='9'){
24         n=(n<<1)+(n<<3)+(c&15);
25         c = getchar();
26     }
27     return n;
28 }
29 int main()
30 {
31     N=read();
32     K=read();
33 //    while((N=read())&&(K=read())){
34         ans=0;
35         for(int i=1;i<=N*3;i++)
36             pre[i]=i;
37         for(int i=0;i<K;i++){
38             int opt,u,v;
39             cin>>opt>>u>>v;
40             if(u>N||v>N){
41                 ans++;
42                 continue;
43             }
44             if(opt==1){
45                 if(find(u)==find(v+N)||find(v)==find(u+N)){//u吃v或者v吃u(这个最后写,第5好写)
46                     ans++;
47                     continue;
48                 }
49                 pre[u]=v;//(这下面几行第2好写)
50                 pre[u+N]=v+N;
51                 pre[u+N+N]=v+N+N;
52             }
53             if(opt==2){
54                 if(find(u)==find(v)||find(v)==find(u+N)){//左操作数uv同类(这个第1好写),右操作数v吃u(第4好写,其实看似是需要或A吃B里的,或B吃C里的,C吃A里的,但没必要写,你只要写一个就行,因为都赋值了,只要某吃某,所有集群都是这个指向关系)
55                     ans++;
56                     continue;
57                 }
58                 pre[u]=v+N;//这下面几行第3好写
59                 pre[u+N]=v+N+N;
60                 pre[u+N+N]=v;
61             }
62             cout<<ans<<endl;
63         }
64 //    }
65 }
View Code

发现大括号弄错了,但改对后居然MLE了???

 1 #include<stdio.h>
 2 #include<string.h>
 3 #define MAX 50001
 4 #include<iostream>
 5 using namespace std;
 6 int N,K;
 7 int ans;
 8 int pre[MAX*3];
 9 int find(int x)//找根
10 {
11     if(x==pre[x])
12         return x;
13     pre[x]=find(pre[x]);
14     return pre[x];
15 }
16 //inline int read(){
17 //    char c=getchar(); int n=0;
18 //    while(c<'0'||c>'9'){
19 //        if(c==EOF)
20 //            return 0;
21 //        c = getchar();
22 //    }
23 //    while(c>='0'&&c<='9'){
24 //        n=(n<<1)+(n<<3)+(c&15);
25 //        c = getchar();
26 //    }
27 //    return n;
28 //}
29 int main()
30 {
31 //    N=read();
32 //    K=read();
33 cin>>N;
34 cin>>K;
35 //    while((N=read())&&(K=read())){
36     ans=0;
37     for(int i=1;i<=N*3;i++)
38         pre[i]=i;
39     for(int i=0;i<K;i++){
40         int opt,u,v;
41         cin>>opt>>u>>v;
42         if(u>N||v>N){
43             ans++;
44             continue;
45         }
46         if(opt==1){
47             if(find(u)==find(v+N)||find(v)==find(u+N)){//u吃v或者v吃u(这个最后写,第5好写)
48                 ans++;
49                 continue;
50             }
51             pre[find(u)]=v;//(这下面几行第2好写)
52             pre[find(u+N)]=v+N;
53             pre[find(u+N+N)]=v+N+N;
54         }
55         if(opt==2){
56             if(find(u)==find(v)||find(v)==find(u+N)){//左操作数uv同类(这个第1好写),右操作数v吃u(第4好写,其实看似是需要或A吃B里的,或B吃C里的,C吃A里的,但没必要写,你只要写一个就行,因为都赋值了,只要某吃某,所有集群都是这个指向关系)
57                 ans++;
58                 continue;
59             }
60             pre[find(u)]=v+N;//这下面几行第3好写
61             pre[find(u+N)]=v+N+N;
62             pre[find(u+N+N)]=v;
63         }
64     }
65     cout<<ans<<endl;
66 } 
View Code

不知道为啥MLE,MLE先不管

知道哪里错了,但不会改了

没招了看了下高潮博客,给我看小脑萎缩了,这为啥opt为1的时候,赋值是 fa[find(u)] = find(v); ,不对啊,就拿他博客里的图

 来说,如果

4 3
1 1 3
2 2 4
2 3 2

数据是这个,现在我要来一个1 1 5,1跟5同类,那这直接1的根是4,我tm直接让4指向了5???啥道理???如图

1指向3指向4指向5,好tm玄妙啊艹

捋顺一下,在我判断的时候,只判断(顺时针)下一个即被反吃,(逆时针)上一个即吃他,uv根相等即同类 —— 真的好神奇啊,只会意会不可言传的感觉,不愧是小无相功

然后至于你吃谁或者跟谁有关系,我不管,我跟着你一起。我理解就是,一条线路上,比如1指向3指向4指向5,这条路既可以用根相等判断同类or互吃关系,接下来的每次赋关系,都会带着这一串已经有的关系图,所以每次都要find找根去搞。所以我写的代码里用 pre[find(u)]=v; 是有问题的,如果u已经有了一个完美的一串关系,你直接来个v把关系搞没了

对比总结:种类并查集,判断两个动物关系,并不是直接判断,而是看现存的图里是否有与他矛盾的关系,如果没有则认为这个关系是对的,并且在所有集群中赋上这种关系

我这是根据高潮博主实际代码画的图即逆着的,我写个跟他讲述图里一样的顺着存的

直接AC

AC代码(种类并查集) —— 三个平台均可AC,多组输入依旧过不了

 1 #include<stdio.h>
 2 #include<string.h>
 3 #define MAX 50001
 4 #include<iostream>
 5 using namespace std;
 6 int N,K;
 7 int ans;
 8 int pre[MAX*3];
 9 int find(int x)//找根
10 {
11     if(x==pre[x])
12         return x;
13     pre[x]=find(pre[x]);
14     return pre[x];
15 }
16 inline int read(){
17     char c=getchar(); int n=0;
18     while(c<'0'||c>'9'){
19         if(c==EOF)
20             return 0;
21         c = getchar();
22     }
23     while(c>='0'&&c<='9'){
24         n=(n<<1)+(n<<3)+(c&15);
25         c = getchar();
26     }
27     return n;
28 }
29 int main()
30 {
31     N=read();
32     K=read();
33 //    while((N=read())&&(K=read())){
34     ans=0;
35     for(int i=1;i<=N*3;i++)
36         pre[i]=i;
37     for(int i=0;i<K;i++){
38         int opt,u,v;
39 //        cin>>opt>>u>>v;
40 opt=read();
41 u=read();
42 v=read();
43         if(u>N||v>N){
44             ans++;
45             continue;
46         }
47         if(opt==1){
48             if(find(u)==find(v+N)||find(v)==find(u+N)){
49                 ans++;
50                 continue;
51             }
52             pre[find(u)]=find(v);
53             pre[find(u+N)]=find(v+N);
54             pre[find(u+N+N)]=find(v+N+N);
55         }
56         if(opt==2){
57             if(find(u)==find(v)||find(v)==find(u+N)){
58                 ans++;
59                 continue;
60             }
61             pre[find(u)]=find(v+N);
62             pre[find(u+N)]=find(v+N+N);
63             pre[find(u+N+N)]=find(v);
64         }
65     }
66     cout<<ans<<endl;
67 }

感觉思路好僵硬,感觉始终无法真正理解这个种类并查集精髓。

现在去处理之前MLE的问题,你返回个WA我可以接受,返回个MLE很诡异啊,决定探明究竟,我把洛谷的MLE数据下载了下来(依旧是上传文件),答案是1322,这么多行,我每次cout i,发现到296行就出问题了,故MLE数据简化为此:

6000 300
2 4625 862
2 2788 4751
2 1580 1618
2 259 5130
2 5878 2956
2 1469 3285
2 5134 258
2 2723 2910
2 4793 1140
2 2626 1264
2 3866 2759
2 943 98
1 2963 5668
2 2907 3126
2 3417 4303
1 3307 5623
2 157 1277
1 1267 2732
2 5316 3735
2 5425 2357
1 3560 3585
2 436 3714
2 355 4634
2 4981 2763
2 2142 988
1 3341 5704
2 2940 2521
1 1150 1332
2 5388 12
1 1135 592
1 289 3950
2 2952 1318
1 5994 5738
2 4838 5558
1 5821 5462
1 4518 4830
2 605 1439
1 2988 5360
2 3394 3360
2 1968 4661
1 1024 5228
1 2133 2971
2 4040 5941
2 2525 6000
1 35 4122
2 2818 4977
1 5791 215
1 4344 1449
2 5401 5509
1 5884 59
2 2351 5677
1 5614 1421
2 1766 259
2 5214 4318
1 4794 3300
1 5364 4403
2 5585 2589
1 4155 1129
2 3946 5791
2 665 5178
1 4314 132
2 4036 60
2 1672 1446
1 5649 5142
2 5440 2746
1 5150 3145
2 4714 1188
2 3887 5844
2 3548 4312
1 2474 2294
2 1089 419
1 3391 4232
2 1643 5212
2 5582 4977
2 5777 1640
2 4214 2798
1 5016 3355
2 4544 4315
1 3120 5833
2 5943 4048
2 5478 1051
1 5007 13
1 3247 37
2 5195 1630
2 1651 3409
2 1071 2762
2 107 5309
1 2562 4234
1 2796 2050
1 4501 5755
2 5297 5247
2 3591 1123
2 2065 2359
2 5963 3187
2 3003 978
2 2979 4181
2 3010 2407
1 5580 2753
2 3752 4361
1 5886 5102
2 365 759
2 699 5889
2 1151 4679
2 560 454
1 3131 2720
2 3137 5095
2 5405 2163
2 96 5139
2 63 1331
1 2271 703
2 1603 4837
2 5321 239
2 1852 319
1 921 3996
2 688 3127
1 2108 1556
1 4636 5639
1 5978 3707
2 1531 461
2 4018 1595
2 4286 5964
1 4099 1963
2 792 752
2 911 118
2 5402 911
2 17 4929
2 5292 1850
2 2511 1965
2 2558 1511
2 870 5356
2 2877 4549
2 3378 5788
2 2621 4721
2 619 3839
2 4523 5080
2 5415 4857
1 2425 5317
2 4366 2424
2 3941 3158
1 1469 2663
1 5863 2041
2 1011 5260
2 2901 290
2 3169 1526
2 3539 3916
1 5237 2953
1 5547 1386
1 640 1828
1 5746 4493
2 4913 457
1 1356 1253
1 4070 3928
2 2700 2381
2 3099 4521
1 3300 3113
1 4274 5353
2 5366 2427
1 2051 721
1 1888 4014
2 2089 2752
2 2918 4970
1 309 4724
2 5785 3399
1 3157 1620
2 133 201
1 1776 2577
2 2587 3335
2 3450 1247
1 1817 679
2 5143 4749
1 646 2593
1 5562 1707
2 2959 5734
2 1587 4000
2 5748 11
2 1905 5130
1 4625 5411
1 967 534
2 4766 2053
2 4268 939
2 5866 2820
1 5391 645
1 5965 5380
2 3767 923
1 2473 4997
1 1230 3134
2 3729 975
2 1989 296
2 3822 945
2 1454 5646
1 304 3302
1 66 1850
2 1052 4590
2 1401 3221
1 3916 5092
1 2953 1171
2 1386 3005
2 1828 467
2 4493 1657
2 457 4716
2 1253 62
1 3928 5406
2 2381 1439
2 4521 3348
1 3113 3033
2 5353 2354
1 2427 2852
2 721 3447
2 4014 1824
2 2752 5898
2 4970 1475
2 4724 1481
1 3399 5779
2 1620 4019
1 201 4991
1 2577 4281
1 3335 56
2 1247 3712
1 679 547
1 4749 3293
1 2593 2154
1 1707 5779
2 5734 5426
1 4000 1455
1 11 4939
2 5130 1706
1 5411 5738
2 534 5299
1 2053 2736
2 939 1133
2 2820 861
1 645 226
2 5380 704
2 923 3688
1 4997 1722
2 3134 2465
2 975 3378
2 296 1950
2 945 793
2 5646 175
2 3302 4448
2 1850 1254
1 4590 4026
2 3221 1796
2 5092 3169
2 1171 3539
2 3005 5237
1 467 5547
2 1657 640
2 4716 5746
2 62 4913
1 5406 1356
1 1439 4070
2 3348 2700
2 3033 3099
2 2354 3300
2 2852 4274
2 3447 5366
2 1824 2051
2 5898 1888
2 1475 2089
2 1481 2918
1 5779 309
2 4019 5785
2 4991 3157
2 4281 133
1 56 1776
1 3712 2587
1 547 3450
2 3293 1817
2 2154 5143
2 5779 646
2 5426 5562
2 1455 2959
1 4939 1587
1 1706 5748
2 5738 1905
2 5299 4625
2 2736 967
2 1133 4766
2 861 4268
2 226 5866
2 704 5391
2 3688 5965
2 1722 3767
2 2465 2473
2 3378 1230
2 1950 3729
2 793 1989
1 175 3822
1 4448 1454
1 1254 304
1 4026 66
1 1796 1052
2 3169 1401
2 3539 3916
1 5237 2953
1 5547 1386
1 640 1828
1 5746 4493
View Code

把用MLE代码用找不同different网站对比下发现,根本原因在与

pre[find(u)]=v;
            pre[find(u+N)]=v+N;
            pre[find(u+N+N)]=v+N+N;
View Code

 pre[u]=v;
            pre[u+N]=v+N;
            pre[u+N+N]=v+N+N;
View Code

任意删除几行,看看是输入的那行数据出现的问题还是因为这条数据导致跟前面关系有冲突(这句话不严谨,大概这个意思),如果是这条数据导致的就麻烦了,我换其他数据就没问题的话,那就要实际去看300行到底啥状况,而如果是前面有冲突那好办,爷爷我直接把前面删几行,压缩数据行数,看的方便,实验了下,发现压缩行数依旧有错,说明我可以类比将数据压缩,开始大胆压缩,跟tm玩扫雷一样,草泥马搞到了4:19

最后数据精简为:

13 10
1 3 5
1 11 3
2 12 2
2 5 4
2 10 9
2 8 1
2 9 3
2 13 6
1 3 5
1 7 10
View Code

代码:(我用注释缩小范围排查的,晚睡脑子不好使了,10+13一直算成26导致半天没看出问题)

 1 //MLE:
 2 #include<stdio.h>
 3 #include<string.h>
 4 #define MAX 50001
 5 #include<iostream>
 6 using namespace std;
 7 int N,K;
 8 int ans;
 9 int pre[MAX*3];
10 inline int read(){
11     char c=getchar(); int n=0;
12     while(c<'0'||c>'9'){
13         if(c==EOF)
14             return 0;
15         c = getchar();
16     }
17     while(c>='0'&&c<='9'){
18         n=(n<<1)+(n<<3)+(c&15);
19         c = getchar();
20     }
21     return n;
22 }
23 int find(int x)//找根
24 {
25     if(x==pre[x])
26     {
27     cout<<"find里:"<<x<<endl;
28         return x;
29     }
30     pre[x]=find(pre[x]);
31     cout<<"pre[]:"<<pre[x]<<endl;
32     return pre[x];
33 }
34 int main()
35 {
36     freopen("zhishu.txt","r",stdin);
37     N=read();
38     K=read();
39     ans=0;
40     for(int i=1;i<=N*3;i++)
41         pre[i]=i;
42     for(int i=1;i<=K;i++){
43         int opt,u,v;
44         opt=read();
45         u=read();
46         v=read();
47         if(u==7){
48             for(int i=1;i<=3*N;i++)
49             cout<<i<<" "<<pre[i]<<endl;
50 
51         }
52         if(u>N||v>N){
53             ans++;
54             continue;
55         }
56         if(opt==1){
57             find(u);
58 //            cout<<v<<N<<endl;
59         find(v+N);
60         cout<<"#"<<endl;
61             if(find(u)==find(v+N)){//}||find(v)==find(u+N)){
62                 ans++;
63                 continue;
64             }
65             pre[find(u)]=v;
66 //            pre[find(u+N)]=v+N;
67 //            pre[find(u+N+N)]=v+N+N;
68 cout<<"————"<<v<<endl;
69         }
70         if(opt==2){
71 //            if(find(u)==find(v)||find(v)==find(u+N)){
72 //                ans++;
73 //                continue;
74 //            }
75             pre[find(u)]=v+N;
76             pre[find(u+N)]=v+N+N;
77             pre[find(u+N+N)]=v;
78             cout<<v+N<<" "<<v+N+N<<" "<<v<<endl;
79         }
80         cout<<""<<i<<" "<<ans<<endl;
81         cout<<endl;
82     }
83 }
View Code

再抽丝剥茧就是,per[17]=5,pre[5]=17死循环了(用上面代码运行精简数据即可知道,23指35指3指17指5指17)。这种互相指向,即之前最短路里的正环。

同时也更加理解了种类并查集,种类并查集再涉及图例子中有环吃的情况,本已经有了12(2)指向9(4),现在来了个3指向12(2),那直接3指向9(4),就很巧妙的避开了,永远不会出现死循环的环。

而我写的那个,赋值没束缚了导致会出现互相指的情况

这些都是经过这么久执着于找之前错误代码MLE看似毫无意义的bug所发现的细节

 

洛谷题解好多解法啊,这群中学生是真tm牛逼没边了,之前看最多的就是种类并查集和带权并查集,╮(╯▽╰)╭唉,强迫症硬着头皮把带权并查集也学了吧

下面筛选了很多不同博客里讲解好的地方放了出来,我是结合着看的

学一手带权并查集(天泽龟),好难啊,看不下去了 

理论文字叙述我是真他妈的看不懂啊,直接把自己当大和尚小和尚手写代码的过程,不行太复杂了,百度找了个简单的带权并查集,看了一个一个(里面的“这代码是肿么回事呢?”这句上面的代码我就研究好一会,自己结合图想比看他讲清楚的多,但大佬太强了还是看不懂,汗颜,居然是放松而写),后又看了很多洛谷带权题解(songhn的),其中这个博客里,“比如两条链”那里说的很棒

 

发现A指向F1到F2和A指向B到F2都有一个很神奇的计算套路,都是AF1+F1F2==AB+BF2,看似很合理,但却是内含了个“关系”这个非显性可见的且非数字距离的东西啊,这有点无法理解,洛谷很多题解都如此,而在上面“看了一个又一个”里的第二个里(即知乎Atri​大佬总结的),这个套路总结的尤为明显

最后结合洛谷songhn的那个穷举表(感觉没画全,应该3*3*3种,比如少了个110天泽龟题解,反复读,第二天想通了,根据天泽龟的图 —— 这个图对我来说相当重要,理解天泽龟代码、写这篇博客、写代码的时候,都一直分屏看着这个图,后面简称“高潮图”

 

自己画了个全网都没有的打表,总共18种情况

简单解释下,我按照洛谷天泽龟题解里说的,

  • 0--> 同种动物
  • 1--> 捕食关系
  • 2--> 被捕食关系

输入的数据,只可能值同类或者吃,所以x只有0和1,画完惊了,才发现居然真的是:re[f1]=x+re[b]−re[a]。将012意义怎么换都符合这个式子(之前我还在想会不会是巧合,而且如果一条路是100和99,另一条路是1和2咋办,这就不深想了,姑且自圆其说理解成模一定是一样的吧,带权并查集太jb高深了)

相比之下这博客里的打表图就太垃圾了,为什么我学个东西这么费劲啊,他们那么轻松的就掌握了,他们到底是真懂假懂啊。

然后看到天泽龟写的“查找(路径压缩)”一下就都连上了

对比总结:不同于上面的种类并查集,带权并查集在判断两个动物关系时,是直接判断(其实不好界定)

 

我理解不了其中一些细节,把自己当作大和尚小和尚画了个图,(代码用的天泽龟那个)

那么又想了下,压缩路径是否有必要?可否不压缩路径呢?

之前测试过,压缩路径只找你终极顶点,终极顶点是啥不会变,只是影响找的时间,而这个题意又把这个找的层数限定在了经过一层两层后会立马再回来,比如,我吃你,你吃了他,那他一定吃我,不会再吃其他人,当然这个不影响结论,只是说压缩路径并没有减少多少,因为本身最多就两层。所以单纯存顶点即种类并查集那种做法,压缩路径可有可无,有了只是优化时间(尽管这个题意摆在那,使得没压缩多少)

但见上图中“想下压缩路径”那句话,带权并查集就不能去掉压缩路径,看爹给你解释下,你瞅我图中“★1”那里,1走3到终极顶点4,我去find的时候(find函数里那个数学公式可以看天泽龟里查找路径压缩下那个图),见“★2”,1直接指向了4(即fa),关系re也更新了,(这时候上面“一个又一个”里的第二个(Atri的),搜那文章里的“都已经被更新”,去好好理解这句话更有帮助),那此时形成的四角边是“★2”里那个

1指向4为高潮图里的re[a]

1指向5为高潮图里的x(此时x是0因为是同类,尽管输入是1 1 5但我判断的时候用1,而存数据的时候用0作为同类,没什么影响)

5指向5为初始5的根为高潮图里的re[b]

那么re[f1]就是4指向5所要求的,

想一下,如果不压缩路径,那么其他都没变,我用的re[a]就会出差错,本来想的是re[a]当作你1直接指向终极顶点4的关系re值,不压缩路径,根虽然会找到,但就会有1指向3的re值,3指向4的re值,所以你还得去迭代遍历的算出1到终极顶点4的直接re

当我继续往下读天泽龟代码的时候发现压缩路径另一个好处是(或者说没有压缩路径,这里根本没法弄), if(f1==f2&&re[a]!=re[b]) 一开始我就在想,万一前面就是不同的关系咋办,现在懂了,压缩路径的时候,已经给都挂在同根上了

另外 else if(f1 != f2){ 这句话其实也是个很好的剪枝,直接写成else也可AC,但会把f1==f2和re[a]==re[b]也弄进来一起做合并,但注意这种情况表示之前已经有过没必要再搞一遍合并

再继续看如果p==2,这句话, int rela=(re[a]-re[b]+3)%3; 一开始很不理解,自己画出来后来发现同类rela为0,吃反了rela会为2。——(-1+3)% 3真JB巧妙啊艹

 

 

以上也是天泽龟说的“然后一些小问题又没啥好说了”的一些展开 —— 带权并查集真tm复杂,纯纯数学,叫关系并查集得了,小无相功并查集

至此再总结一下:带权并查集里的fa只是你的前面的节点也可以叫父节点,而find才是真正找根,但fa是逐渐学习强化趋近于find值的。re是关系数组,也是记录你跟前面的节点的关系,当fa被find函数强化为直指向终极根的时候,re关系也随之变为了和终极根的关系

 

 

 

麻痹的这题快写“一年”了,这并查集真tm费时间,最后自己写一下代码得了。

自己写的时候关于opt==2,对于数据2 u v,怎么判断是否v吃了u,画了个图

不写真的不行,又发现许多其他细节都在代码注释里 

经过多次修改更加深刻后直接AC

AC代码(带权并查集写法) —— 三个平台均可AC

 1 #include<stdio.h>
 2 #include<iostream>
 3 #define MAX 50001
 4 using namespace std;
 5 int N,K;
 6 int re[MAX];
 7 int pre[MAX];
 8 int ans;
 9 int find(int x)
10 {
11     int tp=pre[x];//至关重要,后加的
12     if(x==pre[x])
13         return x;
14     pre[x]=find(pre[x]);
15 
16     re[x]=(re[x]+re[tp])%3;//不能跟上一行换顺序,因为那时候re还没更新呢,自己画个1指向3指向4指向7就知道了,权为2 2 1
17 //re那行,经过调试才发现的重大问题,不写真不知道,re更新变了,pre[x]也变了,就比如高潮博客里的数据:
18 //4 5
19 //1 1 3
20 //2 2 4
21 //2 3 2
22 //1 1 4到这里1本应该指向4,re是2+0,结果这样写就变成了指向4但加的pre[x]本应该是3的re,结果这样弄成了4的re0
23 //2 2 1
24 
25 
26     return pre[x];
27 }
28 int main()
29 {
30     ans=0;
31     cin>>N>>K;
32     for(int i=1;i<=N;i++)
33         pre[i]=i,re[i]=0;//学到新写法
34     for(int i=0;i<K;i++){
35         int opt,u,v;
36         scanf("%d%d%d",&opt,&u,&v);
37 //        cin>>opt>>u>>v;
38         if((u>N ||v>N) || ((opt==2)&&(u==v))){//最后一个或只是剪枝而已,后面opt==2里也会判断到它
39             ans++;
40 //            cout<<"垃圾"<<endl;
41             continue;
42         }
43         //下面跟天泽龟代码不同
44         if(opt==1){
45             int root1=find(u);
46             int root2=find(v);
47 //            if(u==1&&v==4)
48 //                cout<<"——"<<root1<<" "<<re[1]<<" "<<re[3]<<" "<<re[4]<<endl;
49             if(root1!=root2){
50                 pre[root1]=root2;
51                 if((0+re[v]-re[u])>=0)
52                     re[root1]=(0+re[v]-re[u])%3;
53                 if((0+re[v]-re[u])<0)
54 //                    re[root1]=(-(0+re[v]-re[u]))%3;//这样写不行,才发现+3再取模的真正意义,并不是直接取绝对值的意思,用我那个打表图里0 0 2 1就可以看出来
55                     re[root1]=(3+(0+re[v]-re[u]))%3;
56             }
57 //            else if((root1==root2)&&(re[root1]!=re[root2])){//一开始只写了&&左边
58             else if((root1==root2)&&(re[u]!=re[v])){
59 //                cout<<"#"<<re[u]<<" "<<re[v]<<endl;
60                 ans++;
61             }
62         }
63         if(opt==2){
64             int root1=find(u);
65             int root2=find(v);
66 //            if(re[root1]==re[root2]){//分开写好调试排查问题,同根这样判断有问题
67 //            if((root1==root2) && (re[root1]==re[root2])){
68             if((root1==root2) && (re[u]==re[v])){
69 //                cout<<"@"<<root1<<" "<<re[root1]<<endl;
70                 ans++;
71                 continue;
72             }
73 
74 //            if((root1==root2) && (re[root2]-re[root1]+3)%3==2){//突然发现这个相减的顺序有差别,一定不能反,不是差的绝对值那么简单
75             if((root1==root2) && (re[u]-re[v]+3)%3==2){//突然发现这个相减的顺序有差别,一定不能反,不是差的绝对值那么简单
76 //                cout<<"!"<<endl;
77                 ans++;
78                 continue;
79             }
80             pre[root1]=root2;
81             if((1+re[v]-re[u])>=0)//这个时候的re[b]就已经是b到最终极顶点root2的re了
82                 re[root1]=(1+re[v]-re[u])%3;
83             if((1+re[v]-re[u])<0)
84                 re[root1]=(3+(1+re[v]-re[u]))&3;
85 //            if(u==3&&v==2)
86 //                cout<<"^"<<re[3]<<" "<<root2<<" "<<re[root1]<<endl;
87         }
88     }
89     cout<<ans<<endl;
90 }
91 //代码看似很灵活,跟天泽龟不一样,但其实还是无法真正忘记,因为已经钻研了很久,代码已经刻在脑子里了,无法做到只想算法思路不回忆别人的代码了

 

 

Tips:

###:关于A吃B,B吃C,C吃A,好奇查了下食物链食物链三角关系,发现小时候没好好学生物地理历史现在兴趣相当浓厚,那时候没意识到知识有用有趣

###:Adblock规则

  1 luogu.com.cn##.info
  2 luogu.com.cn##.footer
  3 ||cdn.luogu.com.cn/upload/image_hosting/8uzmuj4p.png
  4 luogu.com.cn##.lfe-form-sz-small
  5 blog.csdn.net##.aside-content
  6 ||csdnimg.cn/release/blogv2/dist/pc/img/btnGuideSide1.gif
  7 blog.csdn.net##.show-txt
  8 blog.csdn.net##.csdn-side-toolbar
  9 ||img-home.csdnimg.cn/images/20240218021830.png
 10 blog.csdn.net###copyright-box
 11 blog.csdn.net##.recommend-item-box.type_blog.clearfix
 12 blog.csdn.net##.recommend-item-box.baiduSearch.clearfix
 13 blog.csdn.net##.title-box
 14 blog.csdn.net##.left-toolbox
 15 blog.csdn.net##.recommend-item-box.type_download.clearfix
 16 blog.csdn.net##.blog_container_aside
 17 blog.csdn.net##.aside-title
 18 baidu.com###s_main
 19 baidu.com##.main.clearfix.c-wrapper.c-wrapper-l
 20 baidu.com###s-top-left
 21 baidu.com##.s-bottom-layer-content
 22 baidu.com###bottom_layer
 23 baidu.com##.s-bottom-layer.s-isindex-wrap
 24 baidu.com###u1
 25 baidu.com##.s-top-right.s-isindex-wrap
 26 baidu.com##.s-center-box
 27 baidu.com###s_top_wrap
 28 baidu.com##.s-top-wrap.s-isindex-wrap
 29 poj.org##p[style="font-family:Arial, Helvetica, sans-serif"]
 30 ||poj.org/images/top.gif
 31 ||poj.org/images/home.gif
 32 ||poj.org/images/goback.gif
 33 baidu.com##.cr-title.c-clearfix
 34 baidu.com##.cover-img-boder_1-OG1.c-img-radius-large
 35 baidu.com###content_right
 36 baidu.com##.cr-offset
 37 baidu.com##.FYB_RD
 38 baidu.com##.container_EBGt2.has-attr_1DAxq.fold_2kZgh
 39 baidu.com###con-ar
 40 baidu.com###searchTag
 41 baidu.com##.tag-container_ksKXH
 42 baidu.com###foot
 43 baidu.com##.foot-container_2X1Nt
 44 ||cn.bing.com/th?id=OHR.HauntedEdinburgh_ZH-CN1461834159_1920x1080.jpg&w=720
 45 blog.csdn.net##.recommend-item-box.type_c_download.clearfix
 46 blog.csdn.net##a[style="color:#FC5531;"]
 47 msn.cn##.consumption-page-rail-wrapper
 48 blog.csdn.net##.skill-tree-box
 49 ||img-home.csdnimg.cn/images/20230921102607.png
 50 blog.csdn.net##.toolbar-btn.toolbar-btn-vip.csdn-toolbar-fl
 51 mp.csdn.net##.csdn-side-toolbar
 52 ||360doc.com/OneVip/vipnewtips.aspx?type=1&ref=2&callback=vipnewtipsiframecb&callback2=vipnewtipsiframecb2&aid=undefined
 53 360doc.com##.vipact
 54 360doc.com##.footerji
 55 360doc.com##.foot
 56 360doc.com##.footerclear
 57 cloud.tencent.com##.cdc-widget-global__btn.star
 58 cloud.tencent.com##.cdc-top-ad
 59 cloud.tencent.com##.tea-bubble__inner
 60 cloud.tencent.com##.cdc-card__inner
 61 cloud.tencent.com##.cdc-widget-global__btn.code
 62 cloud.tencent.com##.cdc-widget-global__btn.announcement
 63 cloud.tencent.com##.cdc-layout__side
 64 cloud.tencent.com##.ad-text__x1f
 65 cloud.tencent.com##.cdc-footer__main
 66 cloud.tencent.com##.cdc-footer__recommend
 67 cloud.tencent.com##.cdc-footer__copyright
 68 cloud.tencent.com##.cdc-answer-recommend__title
 69 cloud.tencent.com##.cdc-article-panel-response
 70 easylearn.baidu.com##.vip-banner
 71 easylearn.baidu.com##.vip-banner-cont
 72 baidu.com##.c-trust-as.baozhang-new-v2.baozhang-new
 73 baidu.com##.c-color-gray
 74 baidu.com##.c-icon.icon_X09BS
 75 developer.aliyun.com##.WidgetContent-aliyun-service-ai-assistant-8096__sc-lxtt5w-1.bEgXPh
 76 developer.aliyun.com##._539dc1cd8b1f9a074906eb63131b76cd_link
 77 developer.aliyun.com##._539dc1cd8b1f9a074906eb63131b76cd_banner
 78 developer.aliyun.com##.right-item-box.talk-box
 79 developer.aliyun.com##.right-item-box.ebook-box
 80 developer.aliyun.com##.right-item-box.next-box
 81 developer.aliyun.com##.action-pic.action-shang-normalPic
 82 developer.aliyun.com##.aigc-fixed
 83 blog.51cto.com##.common-section.common-spacing.mb24.user-intr
 84 blog.51cto.com##.top_box
 85 blog.51cto.com##.home-top
 86 blog.51cto.com##.common-section.common-spacing.mb24
 87 blog.51cto.com##.zcht
 88 blog.51cto.com##.header-right
 89 blog.51cto.com##.header-content
 90 blog.51cto.com##.Header
 91 blog.51cto.com##.inner
 92 blog.51cto.com##.minmenu
 93 blog.51cto.com##.hover-ball
 94 blog.51cto.com##.Footer
 95 cnblogs.com##.under-post-card
 96 cnblogs.com##a[style="margin-left:20px"]
 97 cnblogs.com##.tip
 98 cnblogs.com###poweredby
 99 cnblogs.com###footer
100 ||cdn.luogu.com.cn/upload/image_hosting/khxd4u8j.png
101 wenda.so.com##.fr.answer-part-ask-btn
102 wenda.so.com##.main-nav
103 wenda.so.com##.ui-tort
104 wenda.so.com##.fr.answer-part-ico-best
105 wenda.so.com###feedback_detail
106 wenda.so.com##.ui-fadeback
107 wenda.so.com##.ui-weibo
108 wenda.so.com##.task-status-contract
109 wenda.so.com##.ask-btn.js-com-ask-btn
110 wenda.so.com##.search.g-w1000.wrap.clearfix
111 wenda.so.com###so-nav-container--two
112 wenda.so.com##.so-nav-container
113 wenda.so.com##.question-risk-tip.mb10
114 wenda.so.com###detail-leftside-rec
115 wenda.so.com##.js-detail-left
116 wenda.so.com##.mod-detail-normal.pt25.mb30.js-mod-recommend
117 wenda.so.com###bot-flow-wrap
118 wenda.so.com##.mod-detail-normal.pt25.pb20.bot-flow.js-flow
119 wenda.so.com###back_top
120 wenda.so.com##.ui-back-top
121 wenda.so.com##.logo.fl
122 wenda.so.com##.fixed-nav-in.clearfix
123 douyin.com##.douyin-login.subtitle
124 baidu.com##.c-font-medium.list_1V4Yg
125 baidu.com##.c-font-medium.c-color-t
126 163.com##.post_share
127 163.com##.ns-side-totop
128 163.com##.ntes-nav-main.clearfix
129 163.com###js_N_nav
130 163.com##.ntes-nav
131 163.com##.post_top_share_title
132 163.com##.item
133 163.com##.mypurchased_enter_fr
134 163.com##.ns-side-feedback
135 163.com##.post_recommends.js-tab-mod
136 zhihu.com##.css-15m2p8i
137 ||pica.zhimg.com/80/v2-ccdb7828c12afff31a27e51593d23260_720w.png
138 zhihu.com##.css-zkfaav
139 zhihu.com##.css-lv2ren
140 zhihu.com##.Card-header.SimilarQuestions-title
141 zhihu.com##.Card-section.SimilarQuestions-list
142 cnblogs.com###tbCommentBody
143 cnblogs.com##.commentbox_main.comment_textarea
144 cnblogs.com###comment_form_container
145 cnblogs.com##.comment-nav-right
146 ||cdn.luogu.com.cn/upload/image_hosting/p1x9ti01.png
147 blog.csdn.net##.recommend-item-box.type_chatgpt.clearfix
148 ||cdn.luogu.com.cn/upload/image_hosting/27cfcxqd.png
149 luogu.com.cn##.lform-size-small.close.button-transparent
150 ||360doc.com/OneVip/vipnewtips.aspx?type=1&ref=1&callback=vipnewtipsiframecb&aid=1137496761
151 360doc.com###fxbtn_service
152 360doc.com##.fxbtn_service
153 360doc.com###go_top1
154 360doc.com###fxbtn_ai
155 360doc.com##.fxbtn_ai
156 360doc.com###fxbtn_app
157 360doc.com##.fxbtn_app
158 360doc.com###recommendArtHot
159 360doc.com##.his_her
160 360doc.com##.mod__
161 ||pubimage.360doc.com/index7/nlogo.jpg
162 360doc.com###goTop
163 360doc.com##.a2.a3
164 ||cdn.acwing.com/static/web/img/base/national_activity/discount2.png
165 acwing.com###\31 024-close-btn
166 acwing.com##.col-sm-8.copyright
167 acwing.com##.links
168 360doc.com##.prev_next
169 360doc.com##div[style="color:#999;text-align:left;line-height:22px;background:#f7f7f7;padding: 10px 20px;margin-bottom: -7px;margin-top:10px;"]
170 baike.baidu.com##.index-module_navBar__fLItn
171 ||baikebcs.bdimg.com/baike-react/common/logo-baike.svg
172 baike.baidu.com##.lemmaSearchBar
173 baike.baidu.com###J-related-search
174 baike.baidu.com##.relatedSearch_h0f91
175 baike.baidu.com##div[style="background: rgb(245, 245, 245); padding: 40px 0px 10px;"]
176 fanyi.baidu.com##.CmFhmp5c
177 fanyi.baidu.com##.hFEkQwLH
178 fanyi.baidu.com##.sF3Yx_p0
179 fanyi.baidu.com##.URCZyDIb
180 fanyi.baidu.com##._U9afNhR
181 ||img-home.csdnimg.cn/images/20201124032511.png
182 blog.csdn.net###toolbar-search-button
183 blog.csdn.net###toolbar-search-input
184 blog.csdn.net##.toolbar-search-container
185 runoob.com##.feedback-btn.feedback-btn-gray
186 runoob.com##.w-1000.copyright
187 fanyi.baidu.com##.MCT_kzqi
188 fanyi.baidu.com##.X50Qkiei
189 ||cdn.luogu.com.cn/upload/image_hosting/7v9jr201.png
View Code

 

###:之前说做300AC以上的,但想用插图,编辑好了插图,比如这个接过奖杯的罗斯,不然图太多,发现下一个题也是找错误的话,买一送一待会直接把下一个题也切了。发现找错误的话邝斌出了2次(两遍)了。搜索和最短路的重复出现的题(火、倒水、套利),重复,前两个就是并查集模板。最短路最后一题搞的很复杂,记了各种时限,并查集最后一题也搞的复杂,测试记录各种时限

###:夜深人静写算法

###:AC后要看的帖子,先留着(并查集还有这么多分类么):000111

###:唉~~~~(>_<)~~~~╮(╯▽╰)╭耗费了相当大的时间处理基础知识

###:

##########################################################################################无意间又看到这个傻逼垃圾了,整天在这认你爹呢?光我看到的就有3、4次了,傻狗,我打acm学算法的时候这家伙可能都不知道什么叫算法,没那本事就别tm叫讲,叫一起探讨学习。没懒子找茄子
View Code

###:草你奶奶前几天提示我电脑要更新,一直以为禁用了就没管他,结果今天来图书馆发现电脑开不开机了,md昨晚走的时候至少有80%啊,找了几个电源都没反应(后来知道是电源没电吓得我因为电脑报废了艹),换了好几个终于开开了,蓝屏,重启发现提示正在更新,更新完了提示正在清理,完事后开机发现电量就6%。赶紧禁用自动更新

###:

每天作息:23:40闭馆出图书馆,省钱,走3km”山路“,00:40到家,看一章小说逆天邪神,看会视频号猫猫狗狗武松三国武艺值艾佛森罗斯周星驰古惑仔当幸福来敲门贺炜黑人海军中科院博士论文,跑个真实赛车,又想会题写个代码,看电报,每天撸一管子,5:00睡觉,14:00起14:30出门。15:00到饭馆,来去吃个16元自助,15:30吃完,走3km16:10到图书馆,吃个18元茄子肉盖饭,饿的不行买俩馕防止饿死。
View Code

###:天泽龟博客学到的写法: for (int i = 1; i <= n; i++) f[i] = i, re[i] = 0; 

posted @ 2024-11-11 21:49  GerJCS  阅读(14)  评论(0编辑  收藏  举报