P7737-[NOI2021]庆典【tarjan,虚树】

1|0正题

题目链接:https://www.luogu.com.cn/problem/P7737


1|1题目大意

给出一张无向图满足若xz,yz那么有xyyx

q次询问给出起点和终点和k条临时的边,求可能经过点的数量

1n,q3×105,0k2


1|2解题思路

那个条件就是说我们缩点之后可以找出一个联通性和原图相同的树。

先缩点然后和原图相同的树的话我们用拓扑排序找,让每个点入栈的那个点就是它的父节点。

然后因为最多加两条边所以我们可以把有影响的点找出来构成一棵虚树然后暴力跑出答案就好了。

时间复杂度O(n+Qk)


1|3code

#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<stack> #include<queue> #include<cctype> #include<iostream> using namespace std; const int N=3e5+10,Z=18; struct node{ int to,next,w; }a[N]; int n,m,Q,k,dcc,cnt,dfr,top,tot,clt,ans,num,p[7]; int dfn[N],low[N],v[N],ls[N],rt[N],cl[N],dep[N]; int f[N][Z+1],col[N],siz[N],in[N],st[N],dis[N],ed[N]; bool ins[N];stack<int>S;queue<int>q; vector<int>G[N],F[N],T[N],D[N]; inline char Getchar() { static char buf[100000],*p1=buf+100000,*pend=buf+100000; if(p1==pend) { p1=buf; pend=buf+fread(buf,1,100000,stdin); if (pend==p1) return -1; } return *p1++; } inline int read() { char c;int d=1;int f=0; while(c=Getchar(),!isdigit(c))if(c==45)d=-1;f=(f<<3)+(f<<1)+c-48; while(c=Getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48; return d*f; } inline void tarjan(int x){ dfn[x]=low[x]=++cnt; ins[x]=1;S.push(x); for(int i=0;i<G[x].size();i++){ int y=G[x][i]; if(!dfn[y]){ tarjan(y); low[x]=min(low[x],low[y]); } else if(ins[y]) low[x]=min(low[x],dfn[y]); } if(low[x]==dfn[x]){ ++dcc; while(S.top()!=x){ col[S.top()]=dcc; ins[S.top()]=0; siz[dcc]++;S.pop(); } col[x]=dcc;ins[x]=0; siz[dcc]++;S.pop(); } return; } inline void Topsort(){ for(int i=1;i<=dcc;i++) if(!in[i])rt[i]=i,q.push(i); while(!q.empty()){ int x=q.front();q.pop(); for(int i=0;i<F[x].size();i++){ int y=F[x][i];in[y]--; if(!in[y]){ q.push(y); T[x].push_back(y); } } } return; } inline void dfs(int x,int fa){ dis[x]=dis[fa]+siz[x]; dep[x]=dep[fa]+1;dfn[x]=++dfr; for(int i=0;i<T[x].size();i++){ int y=T[x][i]; if(y==fa)continue; f[y][0]=x;rt[y]=rt[x]; dfs(y,x); } ed[x]=dfr;return; } inline int LCA(int x,int y){ if(dep[x]>dep[y])swap(x,y); for(int i=Z;i>=0;i--) if(dep[f[y][i]]>=dep[x])y=f[y][i]; if(x==y)return x; for(int i=Z;i>=0;i--) if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i]; return f[x][0]; } inline bool cmp(int x,int y) {return dfn[x]<dfn[y];} inline void addl(int x,int y,int w){ a[++tot].to=y; a[tot].next=ls[x]; a[tot].w=(dis[y]-dis[x]-siz[y])*w; D[y].push_back(x);ls[x]=tot;return; } inline void Add(int x){ if(rt[st[top]]!=rt[x]){ while(top>1)addl(st[top-1],st[top],1),top--; if(x!=rt[x])st[top]=rt[x],cl[++clt]=x; } if(!top){st[++top]=x;cl[++clt]=x;return;} int lca=LCA(st[top],x); while(top>1&&dep[st[top-1]]>dep[lca]) addl(st[top-1],st[top],1),top--; if(dep[st[top]]>dep[lca])addl(lca,st[top],1),top--; if((!top)||(st[top]!=lca))st[++top]=lca,cl[++clt]=lca; st[++top]=x;cl[++clt]=x; } inline void mark(int x){ v[x]=1; for(int i=0;i<D[x].size();i++) if(!v[D[x][i]]) mark(D[x][i]); return; } inline void calc(int x){ if(v[x])ans+=siz[x];v[x]|=2; for(int i=ls[x];i;i=a[i].next){ int y=a[i].to; if(v[y]&1)ans+=a[i].w,a[i].w=0; if((v[y]&2)||!(v[y]&1))continue; calc(y); } return; } signed main() { freopen("P7737_12.in","r",stdin); freopen("data.out","w",stdout); n=read();m=read();Q=read();k=read(); for(int i=1;i<=m;i++){ int x=read(),y=read(); G[x].push_back(y); } for(int i=1;i<=n;i++) if(!dfn[i])tarjan(i); for(int x=1;x<=n;x++) for(int i=0;i<G[x].size();i++){ int y=G[x][i]; if(col[x]==col[y])continue; F[col[x]].push_back(col[y]);in[col[y]]++; } Topsort();n=dcc; for(int i=1;i<=n;i++) if(rt[i]==i)dfs(rt[i],0); for(int j=1;j<=Z;j++) for(int i=1;i<=n;i++) f[i][j]=f[f[i][j-1]][j-1]; while(Q--){ int s=read(),t=read(); s=col[s];t=col[t]; p[1]=s;p[2]=t;num=2; tot=clt=top=ans=0; for(int i=1;i<=k;i++){ int x=read(),y=read(); x=col[x];y=col[y]; p[++num]=x;p[++num]=y; addl(x,y,0); } sort(p+1,p+1+num,cmp); num=unique(p+1,p+1+num)-p-1; for(int i=1;i<=num;i++)Add(p[i]); while(top>1)addl(st[top-1],st[top],1),top--; mark(t);calc(s); cout<<ans<<'\n'; for(int i=1;i<=clt;i++){ ls[cl[i]]=v[cl[i]]=0; if(D[cl[i]].size())D[cl[i]].clear(); } } return 0; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/15126005.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(105)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示