专栏文章
U606887 ATRI - My Dear Moments
个人记录参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @mio0itzj
- 此快照首次捕获于
- 2025/12/02 11:22 3 个月前
- 此快照最后确认于
- 2025/12/02 11:22 3 个月前
前置算法
并查集
题目分析
首先想到删边不好维护。就应该想到把操作离线下来,按 从大到小排序,这样删边就转换成了加边,很好维护。每次只需要把边权大于等于 的边加入图中,再用并查集维护一下联通快即可。
考虑处理连边操作,每次连边都会让 和 两个点的度数都加一,我们先判断它们连边前的度数是否为二,如果是的话,就要让它们各自的联通块的度数为二的点的总数都要减一,加边后判断同理。
然后考虑如何统计答案。对于每个联通块,我们需要知道里面有多少个点以及度数为二的点有多少个,如果它们数量相等,那么就说明这个联通块是一个环,那么对应的答案就要加一。
维护联通块和点数和度数为二的点数都可以用并查集来处理。代码没有什么细节,注意是离线操作,最后要按原顺序输出答案。
代码
CPP#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1010101;
ll n,m,fa[N],deg[N],deg2[N],cir[N],q,d,ans[N],siz[N];
struct edge{ll u,v,w;}s[N],p[N];
bool cmp(edge a,edge b){return a.w>b.w;}
ll find(ll x){
if(fa[x]==x)return x;
return fa[x]=find(fa[x]);
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++)fa[i]=i,siz[i]=1;
for(int i=1;i<=m;i++)cin>>s[i].u>>s[i].v>>s[i].w;
sort(s+1,s+m+1,cmp);
cin>>q;
for(int i=1;i<=q;i++)cin>>d,p[i]={i,0,d};
sort(p+1,p+q+1,cmp);
ll c=0;
for(int i=1,j=0;i<=q;i++){
while(j<m&&s[j+1].w>=p[i].w){
j++;
ll x=find(s[j].u),y=find(s[j].v);
if(deg[s[j].u]==2)deg2[x]--;
if(deg[s[j].v]==2)deg2[y]--;
deg[s[j].u]++,deg[s[j].v]++;
c-=cir[x],cir[x]=0;
if(x!=y)fa[y]=x,siz[x]+=siz[y],deg2[x]+=deg2[y],c-=cir[y];
if(deg[s[j].u]==2)deg2[x]++;
if(deg[s[j].v]==2)deg2[x]++;
if(deg2[x]==siz[x])c++,cir[x]=1;
}
ans[p[i].u]=c;
}
for(int i=1;i<=q;i++)cout<<ans[i]<<' ';
return 0;
}
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...