1 条题解
-
0Guest LV 0 MOD
-
0
这道題真的是没有时间写数据了,如果你有兴趣也可以看一看。下面那个程序我没有调试过,反正只是留作纪念吧。
这道题的思路:先处理环,用tarjan老套路縮环,之后拓扑排序分层。然后用bitset或者每个点维护400个int型(手搞bitset)表示某个点可以由哪一些点到达。之后分两种情况:1:这次询问的两个点在同一个強連通分量上,直接输出编号小的那一个点。2:这次询问的两个店不在同一个强连通分量上,就可以进行二分答案在哪一层。因为越后面层数上的点可以由更多的点到达,所以这个符合二分的单调性。如果在这一层找不到包含它们两个点路径的点,就扩大搜索的规模,否则缩小规模。最后就把答案所在层数以及那一个点二分出来了。
时间复杂度O(n+n+logn * q)#include<bits/stdc++.h> inline void read(int&a) { a=0;char c=getchar(); while(c<'0'||c>'9')c=getchar(); while(c>='0'&&c<='9') { a=(a<<1)+(a<<3)+c-'0'; c=getchar(); } } inline void write(int a) { if(a<0){a=-a;putchar('-');} if(a>9)write(a/10); putchar(a%10+'0'); } const int maxn=10001; int n,m,d1=0,d=0,q; int next1[maxn],to1[maxn],from1[maxn],point1[maxn]; inline void add1(int a,int b) { next1[++d1]=point1[a]; point1[a]=d1; to1[d1]=b; from1[d1]=a; } struct POINT { int has[400]; inline bool son(int x) { int k=(x-1)/30,t=(x-1)%30; if(has[k]&(1<<t-1))return true; return false; } inline void merge(const POINT&a) { for(int i=1;i<=n/30+1;i++) has[i]=a.has[i]|has[i]; } }have[maxn]; int tt=0; int belong[maxn],stack[maxn],dfn[maxn],end=0; bool in_stack[maxn],vis[maxn]; void tarjan(int p) { vis[p]=true; belong[p]=dfn[p]=++tt; int side=point1[p]; while(side) { if(!vis[to1[side]]) { in_stack[to1[side]]=true; stack[++end]=to1[side]; tarjan(to1[side]); belong[p]=std::min(belong[to1[side]],belong[p]); } else if(in_stack[to1[side]]) { belong[p]=std::min(belong[to1[side]],belong[p]); } side=next1[side]; } if(belong[p]==dfn[p]) { while(stack[end]!=p) { belong[stack[end]]=p; in_stack[stack[end]]=false; --end; } belong[p]=p; in_stack[p]=false; --end; } } int next[maxn],to[maxn],point[maxn],in[maxn]; inline void add(int a,int b) { next[++d]=point[a]; to[d]=b; point[a]=d; ++in[a]; } void dfs(int p) { have[p].has[(p-1)%30]&=1<<p-1; int side=point[p]; while(side) { have[to[side]].merge(have[p]); dfs(to[side]); side=next[side]; } } int start=0,que[maxn]; int in_step[maxn][maxn],step[maxn],maxstep=0; void topo() { while(end>=start) { int p=que[start],side=next[side]; while(side) { --in[to[side]]; if(!in[to[side]]){que[++end]=to[side];step[to[side]]=step[p]+1;} } maxstep=std::max(step[p],maxstep); ++start; } } inline int find(int s,int x,int y) { int ans=INT_MAX; for(int i=1;i<=in_step[x][0];++i) { if(have[in_step[s][i]].son(x)&&have[in_step[s][i]].son(y)) ans=std::min(ans,in_step[s][i]); } if(ans==INT_MAX)return 0; return ans; } int lcson(int x,int y) { if(belong[x]==belong[y])return std::min(x,y); x=belong[x],y=belong[y]; if(!find(maxstep,x,y))return -1; int ans,l=std::max(step[x],step[y]),r=maxstep; while(l!=r) { int mid=l+r>>1; ans=find(mid,x,y); if(!ans)l=mid+1; else r=mid; } return ans; } int main() { memset(vis,false,sizeof(vis)); memset(in_step,0,sizeof(in_step)); memset(in,0,sizeof(in)); memset(in_stack,false,sizeof(in_stack)); memset(point1,0,sizeof(point1)); read(n);read(m);int u,v; for(int i=1;i<=m;i++) { read(u);read(v); add1(u,v); } for(int i=1;i<=n;i++) if(!vis[i]) { in_stack[i]=true; stack[++end]=i; tarjan(i); } for(int i=1;i<=d;i++) if(belong[from1[i]]!=belong[to1[i]])add(from1[i],to1[i]); for(int i=1;i<=n;i++) if(!in[i]&&belong[i]==i){que[++end]=i;step[i]=1;} end=-1; topo(); read(q); int x,y; while(q--) { read(x);read(y); write(lcson(x,y));printf("\n"); } return 0; }
- 1
信息
- 难度
- 10
- 分类
- (无)
- 标签
- (无)
- 递交数
- 1
- 已通过
- 0
- 通过率
- 0%
- 上传者