题意:给定一个有向图,每个节点只有一条出边,现在两个人在两个节点沿着有向边走,按照题意输出相遇时两个人走的路径。
题解:这个有向图很特别,由于每个节点只有一条出边,所以如果形成一个环的话就只能有指向这个环的边,同时一个子图内最多存在一个环,tarjan搞掉环,
建反图虚拟根节点转换成一棵树,根节点如果是环的环用带关系的并查集维护,然后lca->rmq,在线得到答案。
每次lca->rmq总是一串代码…
Sure原创,转载请注明出处。
#pragma comment (linker , "/STACK:1024000000,1024000000") #include <iostream> #include <cstdio> #include <memory.h> #include <cmath> #define MIN(a , b) ((a) < (b) ? (a) : (b)) #define MAX(a , b) ((a) > (b) ? (a) : (b)) using namespace std; const int maxn = 500002; struct node { int v; int next; }edge[maxn << 1]; int up[maxn],down[maxn],head[maxn],father[maxn],dis[maxn]; int dfn[maxn],low[maxn],s[maxn],belong[maxn],cnt[maxn],indegree[maxn]; int E[maxn << 1],D[maxn << 1],bj[maxn],dep[maxn],dp[maxn << 1][20]; bool vis[maxn],instack[maxn]; int m,n,idx,tmpdfn,tot,top,bound; void init() { memset(head,-1,sizeof(head)); memset(cnt,0,sizeof(cnt)); memset(vis,false,sizeof(vis)); memset(instack,false,sizeof(instack)); idx = tmpdfn = 0; tot = 1; return; } inline void in(int &a) { char ch; while(ch = getchar(), ch < '0' || ch > '9'); a = ch - '0'; while(ch = getchar(), ch >= '0' && ch <= '9') { a = a * 10 + ch - '0'; } return; } void swap(int &a,int &b) { int tmp = a; a = b; b = tmp; return; } int find(int u) { if(u == father[u]) return father[u]; int tmp = father[u]; father[u] = find(tmp); dis[u] += dis[tmp]; return father[u]; } void addedge(int u,int v) { edge[idx].v = v; edge[idx].next = head[u]; head[u] = idx++; return; } void read() { for(int i=1;i<=n;i++) { father[i] = i; in(down[i]); addedge(i , down[i]); } return; } void tarjan(int st) { dfn[st] = low[st] = tmpdfn++; vis[st] = instack[st] = true; s[top++] = st; for(int i=head[st];i != -1;i=edge[i].next) { if(vis[edge[i].v] == false) { tarjan(edge[i].v); low[st] = MIN(low[st] , low[edge[i].v]); } else if(instack[edge[i].v]) { low[st] = MIN(low[st] , dfn[edge[i].v]); } } if(dfn[st] == low[st]) { int u; do { u = s[--top]; instack[u] = false; belong[u] = tot; cnt[tot]++; }while(u != st); tot++; } return; } void reset() { memset(head,-1,sizeof(head)); memset(up,-1,sizeof(up)); memset(dis,0,sizeof(dis)); memset(indegree,0,sizeof(indegree)); memset(dep,0,sizeof(dep)); idx = top = 0; return; } void make() { for(int i=1;i<=n;i++) { if(vis[i] == false) { top = 0; tarjan(i); } } reset(); for(int i=1;i<=n;i++) { int u = belong[down[i]]; int v = belong[i]; if(u != v) { addedge(u,v); indegree[v]++; if(cnt[u] > 1) { up[v] = down[i]; } } else { int x = find(down[i]); int y = find(i); if(x != y) { father[y] = x; dis[y] = dis[down[i]] + 1; } } } for(int i=1;i<tot;i++) { if(indegree[i] == 0) { addedge(0,i); } } return; } void dfs(int st,int h) { dep[st] = h; E[++top] = st; D[top] = h; bj[st] = top; for(int i=head[st];i != -1;i=edge[i].next) { if(up[edge[i].v] == -1) { up[edge[i].v] = up[st]; } dfs(edge[i].v , h+1); E[++top] = st; D[top] = h; } return; } void init_rmq() { for(int i=1;i<=top;i++) { dp[i][0] = i; } for(int j=1;j<=bound;j++) { for(int i=1;i + (1 << j) - 1 <= top;i++) { if(D[dp[i][j-1]] < D[dp[i + (1 << (j-1))][j-1]]) { dp[i][j] = dp[i][j-1]; } else { dp[i][j] = dp[i + (1 << (j-1))][j-1]; } } } return; } int askrmq(int l,int r) { if(l > r) swap(l , r); int d = log((double)(r - l + 1)) / log(2.0); int wei = -1; if(D[dp[l][d]] < D[dp[r - (1 << d) + 1][d]]) { wei = dp[l][d]; } else { wei = dp[r - (1 << d) + 1][d]; } return E[wei]; } void solve() { dfs(0,0); bound = log((double)(top + 1)) / log(2.0); init_rmq(); int u,v; while(m--) { in(u),in(v); if(u == v) { puts("0 0"); continue; } int x = belong[u]; int y = belong[v]; int lca = askrmq(bj[x] , bj[y]); if(lca == 0) { puts("-1 -1"); continue; } else if(cnt[lca] == 1) { printf("%d %d\n",dep[x] - dep[lca],dep[y] - dep[lca]); continue; } int dx,dy,dxy,dyx; if(x == y) { dx = dy = 0; find(u),find(v); if(dis[u] < dis[v]) { dxy = cnt[x] + dis[u] - dis[v]; dyx = dis[v] - dis[u]; } else { dxy = dis[u] - dis[v]; dyx = cnt[x] - dxy; } } else { dx = dep[x] - dep[lca]; dy = dep[y] - dep[lca]; if(cnt[lca] == 1) { dxy = dyx = 0; } else { u = (up[x] == -1) ? u : up[x]; v = (up[y] == -1) ? v : up[y]; find(u),find(v); if(dis[u] < dis[v]) { dxy = cnt[lca] + dis[u] - dis[v]; dyx = dis[v] - dis[u]; } else { dxy = dis[u] - dis[v]; dyx = cnt[lca] - dxy; } } } if(MAX(dx+dxy , dy) < MAX(dx , dy+dyx)) { printf("%d %d\n",dx+dxy , dy); } else if(MAX(dx+dxy , dy) > MAX(dx , dy+dyx)) { printf("%d %d\n",dx , dy+dyx); } else { if(MIN(dx+dxy , dy) < MIN(dx , dy+dyx)) { printf("%d %d\n",dx+dxy , dy); } else if(MIN(dx+dxy , dy) > MIN(dx , dy+dyx)) { printf("%d %d\n",dx , dy+dyx); } else { printf("%d %d\n",MAX(dx+dxy , dy),MIN(dx , dy+dyx)); } } } return; } int main() { while(~scanf("%d %d",&n,&m)) { init(); read(); make(); solve(); } return 0; }