【GDOI2015】 水题 tarjan缩点
这一题,我当年只会60分做法。。。。。
我们考虑对原图跑一波边双,然后缩成一个森林。
对于森林中的每一棵树,我们钦定一个根。
令siz[x]表示以x为根的子树中,在原图中点的个数。
令当前的答案为ans
对于一条边(u,v),如果这两个点在缩点后的同个点内,那么什么都不用管,直接输出ans即可。
否则我们先令u=d[u],v=d[v],其中d[i]表示原图中第i号点在缩点后的森林中的编号。
显然这两个点在同一棵树内,不妨设dep[u]>dep[v],令rt表示u所在的树的根。
显然断掉这条边,增加的非联通点对个数为siz[u]×(siz[rt]−siz[u])。
加上ans输出即可。
注意对1000取模!!!
1 #include<bits/stdc++.h> 2 #define L long long 3 #define M 100005 4 using namespace std; 5 6 struct edge{int u,next;}e[M*22]={0}; int head[M]={0},head1[M]={0},use=0; 7 void add(int x,int y){e[use].u=y;e[use].next=head[x];head[x]=use++;} 8 void add1(int x,int y){use++;e[use].u=y;e[use].next=head1[x];head1[x]=use;} 9 int dfn[M]={0},low[M]={0},b[M]={0},d[M]={0},siz[M]={0},cnt=0,t=0; stack<int> s; 10 int n,m,q; 11 void dfs(int x,int fa){ 12 dfn[x]=low[x]=++t; s.push(x); b[x]=1; 13 for(int i=head[x];~i;i=e[i].next) 14 if(i!=fa){ 15 if(!dfn[e[i].u]) dfs(e[i].u,i^1),low[x]=min(low[x],low[e[i].u]); 16 else if(b[e[i].u]) low[x]=min(low[x],dfn[e[i].u]); 17 } 18 if(dfn[x]==low[x]){ 19 cnt++; int u; 20 do{ 21 u=s.top();s.pop(); 22 b[x]=0; d[u]=cnt; siz[cnt]++; 23 }while(u!=x); 24 } 25 } 26 int du[M]={0},dep[M]={0},ff[M]={0}; 27 void dfs1(int x,int fa){ 28 dep[x]=dep[fa]+1; ff[x]=ff[fa]; 29 for(int i=head1[x];i;i=e[i].next) 30 if(e[i].u!=fa) 31 dfs1(e[i].u,x),siz[x]+=siz[e[i].u]; 32 } 33 34 int U[M*10]={0},V[M*10]={0}; 35 int main(){ 36 memset(head,-1,sizeof(head)); 37 scanf("%d%d%d",&n,&m,&q); 38 for(int i=1;i<=m;i++){ 39 int x,y; scanf("%d%d",&x,&y); 40 x++; y++; 41 add(x,y); add(y,x); 42 U[i]=x; V[i]=y; 43 } 44 for(int i=1;i<=n;i++) if(!dfn[i]) 45 dfs(i,-1); 46 for(int x=1;x<=n;x++) 47 for(int i=head[x];~i;i=e[i].next) 48 if(d[x]!=d[e[i].u]){ 49 add1(d[x],d[e[i].u]); du[d[x]]++; 50 } 51 L ans=1LL*n*n; 52 for(int i=1;i<=cnt;i++) 53 if(du[i]==0||(du[i]==1&&dep[i]==0)){ 54 ff[0]=i; dfs1(i,0); 55 ans-=1LL*siz[i]*siz[i]; 56 } 57 ans/=2; 58 while(q--){ 59 int id,x,y; scanf("%d",&id); id++; 60 x=U[id]; y=V[id]; 61 x=d[x]; y=d[y]; 62 if(x==y||ff[x]!=ff[y]){printf("%lld\n",ans%1000); continue;} 63 if(dep[x]<dep[y]) swap(x,y); 64 L minus=1LL*siz[x]*(siz[ff[y]]-siz[x]); 65 printf("%lld\n",(ans+minus)%1000); 66 } 67 }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
2017-10-23 【NOIP2016 Day1 T2】天天爱跑步
2017-10-23 【NOIP2016 Day1 T1】玩具谜题