记录编号 |
577220 |
评测结果 |
AAAAAAAAAA |
题目名称 |
[HDOJ 3686]交通实时查询系统 |
最终得分 |
100 |
用户昵称 |
yuan |
是否通过 |
通过 |
代码语言 |
C++ |
运行时间 |
0.164 s |
提交时间 |
2022-10-26 21:40:49 |
内存使用 |
13.47 MiB |
显示代码纯文本
- #include <bits/stdc++.h>
- using namespace std;
- const int N = 40001,M = 400001;
-
- struct Edge {
- int from,to,nxt;
- }edge[M],edge2[M];
-
- int tot,cnt,head[N],head2[N],num;
-
- void add(int u,int v) {
- edge[++tot].from = u;
- edge[tot].to = v;
- edge[tot].nxt = head[u];
- head[u] = tot;
- }
-
- void add2(int u,int v) {
- edge2[++cnt].from = u;
- edge2[cnt].to = v;
- edge2[cnt].nxt = head2[u];
- head2[u] = cnt;
- }
-
- int dfn[N],low[N],dfnc,n,m,zhan[N],top;
-
- void tarjan(int now,int fa) {//找点双联通分量,缩点,构造圆方树
- dfn[now] = low[now] = ++dfnc;//初始化
- zhan[++top] = now;//当前结点入栈
- for(int i = head[now]; i != -1; i = edge[i].nxt) {
- int succ = edge[i].to;//now-->succ后继
- if(!dfn[succ]) {//未访问
- tarjan(succ,now);
- low[now] = min(low[now],low[succ]);
- if(dfn[now]<= low[succ]) {//now为割点
- num++;//新点,方点
- add2(num,now),add2(now,num);//now和方点连边
- while(1) {//弹出栈中的所有点,这些点属于同一点双
- int x = zhan[top--];
- add2(x,num),add2(num,x);//分别和方点连边
- if(x == succ) break;
- }
- }
- }
- else if(succ!= fa) {//非搜索树边
- low[now] = min(low[now],dfn[succ]);
- }
- }
- }
-
- int f[N][22],dep[N];
- bool vis[N];
-
- void dfs(int now,int fa){
- vis[now] = 1;//访问标记
- dep[now] = dep[fa]+1;//深度
- f[now][0] = fa;//2^0辈祖先
- for(int i = 1; (1<<i) <= dep[now]; i++)//为倍增求LCA准备
- {//求now的2^i辈祖先:now的2^(i-1)辈祖先的2^(i-1)辈祖先
- f[now][i] = f[f[now][i-1]][i-1];//爸爸的爸爸叫爷爷
- }
- for(int i = head2[now]; i!= -1; i = edge2[i].nxt) {
- int succ = edge2[i].to;
- if(succ!= fa && !vis[succ]) {
- dfs(succ,now);
- }
- }
- }
-
- int LCA(int x,int y) {//树上倍增求LCA
- if(dep[x]>dep[y]) swap(x,y);
- int len = dep[y]-dep[x],k = 0;
- while(len) {
- if(len&1) y = f[y][k];
- k++,len >>= 1;
- }
- if(x == y) return x;
- for(int i = 20;i >= 0;i--) {
- if(f[x][i] == f[y][i]) continue;
- x = f[x][i],y = f[y][i];//同时上跳2^i步
- }
- return f[x][0];
- }
-
- int solve(int x,int y) {
- return (dep[x]+dep[y]-2*dep[LCA(x,y)])/2-1;
- }//圆方树:圆点和方点交替出现,故需/2排除方点
-
- int main() {
- freopen("traffic_query.in", "r", stdin);
- freopen("traffic_query.out", "w", stdout);
- while(scanf("%d%d",&n,&m)!= EOF && (n|m))
- {//多组数据
- memset(head,-1,sizeof(head));
- memset(head2,-1,sizeof(head2));
- memset(edge,0,sizeof(edge));
- memset(edge2,0,sizeof(edge2));
- memset(dfn,0,sizeof(dfn));
- memset(low,0,sizeof(low));
- memset(f,0,sizeof(f));
- memset(dep,0,sizeof(dep));
- memset(zhan,0,sizeof(zhan));
- memset(vis,0,sizeof(vis));
- tot = 0,cnt = 0,dfnc = 0,top = 0,num = n;
- for(int i = 1;i<= m;i++) {
- int u,v;
- scanf("%d%d",&u,&v);
- add(u,v); add(v,u);
- }
- for(int i = 1;i<= n;i++)
- {//对点双缩点并构造圆方树
- if(!dfn[i]) tarjan(i,-1);
- }
- for(int i = 1;i<= num;i++)
- {//dfs求结点i的深度和2^x辈祖先
- if(!vis[i]) dfs(i,0);
- }
- int q;
- scanf("%d",&q);
- while(q--) {
- int s,t;
- scanf("%d%d",&s,&t);//起始边
- //边到边 转化为 点到点
- int ans1 = solve(edge[s*2].from,edge[t*2].from);
- int ans2 = solve(edge[s*2].from,edge[t*2].to);
- int ans3 = solve(edge[s*2].to,edge[t*2].from);
- int ans4 = solve(edge[s*2].to,edge[t*2].to);
- int ans = max(max(ans1,ans2),max(ans3,ans4));
- printf("%d\n",ans);
- }
- }
- return 0;
- }