压力
首先如果路径上有割点一定是必经点,然后如果是环上的点(除了割点)一定有多条路径可以到,所以环上(除了割点起点终点)都不必经。
所以点双缩点,重新建图(普通建图or圆方)
那么对于每组询问lca加普通树差标记一下,
对于每组询问拿数组zz记录起点终点,
最后dfs扫一遍
,结束时如果不为割点,直接输出zz
否则输出dfs扫出的ans
必经点模版题
#include<bits/stdc++.h> #define ll long long #define pt printf("******\n") #define A 1000000 using namespace std; ll tot=0,head[A],sta[A],low[A],dfn[A],nxt[A],ver[A],deep[A],belong[A],cut[A]; ll tc=0,head_c[A],nxt_c[A],ver_c[A],sz[A],f[A][30],ans[A],zz[A]; ll n,m,q,t,num=0,cnt=0,root,top=0; vector<ll> scc[A]; bool flag[A],vis[A]; void add(ll x,ll y){ nxt[++tot]=head[x],head[x]=tot,ver[tot]=y; } void add_c(ll x,ll y){ nxt_c[++tc]=head_c[x],head_c[x]=tc,ver_c[tc]=y; } void tarjan(ll x){ low[x]=dfn[x]=++num; sta[++top]=x;ll vis=0; if(x==root&&!head[x]) { cnt++; belong[x]=cnt; scc[cnt].push_back(x); } for(ll i=head[x];i;i=nxt[i]){ ll y=ver[i]; if(!dfn[y]){ tarjan(y); low[x]=min(low[x],low[y]); if(dfn[x]<=low[y]){ vis++; if(x!=root||vis>1) cut[x]=1; cnt++; ll z; do{ z=sta[top--]; belong[z]=cnt; scc[cnt].push_back(z); }while(z!=y); belong[x]=cnt; scc[cnt].push_back(x); } } else low[x]=min(low[x],dfn[y]); } } inline ll lca(ll x,ll y){ if(deep[x]>deep[y]) swap(x,y); ll w; for(w=0;(1<<w)<=deep[y];w++); w--; for(ll i=w;i>=0;i--) { // printf("deep[%lld]=%lld deep[%lld]=%lld f[%lld]=%lld\n",x,deep[x],y,deep[y],i,f[y][i]); if(deep[x]<=deep[f[y][i]]) y=f[y][i]; if(deep[x]==deep[y]) break; } if(x==y) return x; for(ll i=w;i>=0;i--){ if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i]; } return f[y][0]; } void dfs2(ll x,ll de){ deep[x]=de;flag[x]=1; for(ll i=head_c[x];i;i=nxt_c[i]){ ll y=ver_c[i]; if(flag[y]) continue; f[y][0]=x; dfs2(y,de+1); } } ll dfs3(ll x){ vis[x]=1; for(ll i=head_c[x];i;i=nxt_c[i]){ ll y=ver_c[i]; if(vis[y]) continue; ll to=dfs3(y); ans[x]+=to; } return ans[x]; } int main(){ // freopen("mkd.txt","r",stdin); // freopen("wa.txt","w",stdout); scanf("%lld%lld%lld",&n,&m,&q); t=log(n)/log(2)+5; for(ll i=1;i<=m;i++){ ll x,y; scanf("%lld%lld",&x,&y); add(x,y);add(y,x); } for(ll i=1;i<=n;i++){ if(!dfn[i]) root=i,tarjan(i); } num=cnt; for(ll i=1;i<=n;i++) if(cut[i]) belong[i]=++num/*,printf("gd=%lld\n",i)*/; for(ll i=1;i<=cnt;i++){ ll size=scc[i].size(); for(ll j=0;j<size;j++){ if(cut[scc[i][j]]){ add_c(i,belong[scc[i][j]]); add_c(belong[scc[i][j]],i); } } } dfs2(1,1),f[1][0]=1; for(ll j=1;j<=t;j++) for(ll i=1;i<=num;i++) f[i][j]=f[f[i][j-1]][j-1]; /*for(ll i=1;i<=n;i++){ printf("belong=%lld\n",belong[i]); } for(ll i=1;i<=num;i++) { printf("deep[i]=%lld f[i][0]=%lld belong=%lld\n",deep[belong[i]],f[belong[i]][0],belong[i]); }*/ for(ll i=1;i<=q;i++){ ll x,y; scanf("%lld%lld",&x,&y); ll lc=lca(belong[x],belong[y]); // cout<<lc<<endl; zz[x]++,zz[y]++; // printf("x=%lld y=%lld lc=%lld lf=%lld\n",belong[x],belong[y],lc,f[lc][0]); ans[belong[x]]++; ans[belong[y]]++; ans[lc]--; if(f[lc][0]!=lc)ans[f[lc][0]]--; } dfs3(1); for(ll i=1;i<=n;i++){ if(cut[i]) cout<<ans[belong[i]]<<endl; else cout<<zz[i]<<endl; } return 0; }
我已没有下降的余地