专题:数论基础
比上个专题简单一点点,但听说明天会很难...
题目:https://cn.vjudge.net/contest/244425#overview
今天计蒜客组队赛(题库101页),有大佬带我巨开心,我就做了一道.....希望大佬不要丢下我,我会好好学的,嘤嘤嘤。
Question_A
并查集,我觉得难点在,权重的计算上,合并时的转换上,有点迷,试来试去。
#include<cstdio>
#include<cstring>
int weight[200008];
int fa[200008];
int find(int a){
if(fa[a]==-1)
return a;
int root=find(fa[a]);
weight[a]+=weight[fa[a]];
fa[a]=root;
return root;
}
int main(){
int n,m;
int u,v,w;
while(~scanf("%d%d",&n,&m)){
memset(fa,-1,sizeof(fa));
memset(weight,0,sizeof(weight));
int ans=0;
for(int i=0;i<m;i++){
scanf("%d%d%d",&u,&v,&w);
u=u-1;
int x=find(u);
int y=find(v);
if(x!=y){
fa[y]=x;
weight[y]=weight[u]-weight[v]+w;
}
else{
if(weight[v]-weight[u]!=w)
ans++;
}
}
printf("%d\n",ans);
}
}
Question_B
并查集,很经典的一道种类并查集,巨神奇,啊。
#include<cstdio>
#include<cstring>
const int N=50002;
int fa[150010];
int find(int n){
if(fa[n]==-1)
return n;
int root=find(fa[n]);
fa[n]=root;
return root;
}
bool same(int a,int b){
if(find(a)==find(b))
return true;
return false;
}
void unite(int a,int b){
int aa=find(a);
int bb=find(b);
if(aa!=bb)
fa[aa]=bb;
}
int main(){
int n,k;
int d,x,y;
scanf("%d%d",&n,&k);
int ans=0;
memset(fa,-1,sizeof(fa));
while(k--){
scanf("%d%d%d",&d,&x,&y);
if(x>n||y>n){
ans++;
continue;
}
if(d==1){
if(same(x,y+N)||same(x,y+2*N))
ans++;
else{
unite(x,y);
unite(x+N,y+N);
unite(x+2*N,y+2*N);
}
}
if(d==2){
if(same(x,y)||same(x,y+2*N))
ans++;
else{
unite(x,y+N);
unite(x+N,y+2*N);
unite(x+2*N,y);
}
}
}
printf("%d\n",ans);
}
Question_C
BUG的同性恋,昆虫都搞上GAY了》。。
一样我也是用种类并查集写的,没什么核心区别。其他方法到没掌握好(就是不会),还有手写的时候贼慢。
Question_D
贪心算法写的表示巨开心。听说是要用并查集优化,记录。
Question_E
trajan算法求割点数量,并求子连通图数量,好难,模板,码上;
若有k的儿子为i,我们定义AnceDeep[i]为结点i辈分最高(深度最浅)的祖先的深度,deep[k]为k的搜索深度(时间戳),那么 k为割点当且仅当k满足(1)(2)中的一个:
(1)若k为深搜树的根Root,当且仅当k的儿子数(分支数)>=2时k为割点;(这个我有点不能理解,比如本题就不满足啊)
(2)若k为搜索树的中间结点(即k既不为根也不为叶),那么k必然有father和son,若AnceDeep[son]>= deep[k],则k必然为
割点。
参考链接(我的就不上来了):https://blog.csdn.net/crescent__moon/article/details/15028919
Question_H
最小生成树,数据结构学过,终于遇到一道学过的了,加上新学的并查集可以更好的判断环,OK。