【codeforces 983E】NN country

Description

In the NN country, there are n cities, numbered from 1 to n, and n−1 roads, connecting them. There is a roads path between any two cities.

There are m bidirectional bus routes between cities. Buses drive between two cities taking the shortest path with stops in every city they drive through. Travelling by bus, you can travel from any stop on the route to any other. You can travel between cities only by bus.

You are interested in q questions: is it possible to get from one city to another and what is the minimum number of buses you need to use for it?

Input

The first line contains a single integer n (2≤n≤2⋅105) — the number of cities.

The second line contains n−1 integers p2,p3,…,pn (1≤pi<i), where pi means that cities pi and i are connected by road.

The third line contains a single integer m (1≤m≤2⋅105) — the number of bus routes.

Each of the next m m lines contains 2 integers a and b (1≤a,b≤n, a≠b), meaning that there is a bus route between cities a and b. It is possible that there is more than one route between two cities.

The next line contains a single integer q (1≤q≤2⋅105) — the number of questions you are interested in.

Output

Print the answer for each question on a separate line. If there is no way to get from one city to another, print −1. Otherwise print the minimum number of buses you have to use.

 

题意:给定一棵 $n$ 个点的树, $m$ 条链, $q$ 个询问,每次询问 $a$ 到 $b$ 之间的路径最少可用几条给定链完全覆盖,无解输出 $-1$ 

分析:

对于每一条 $a$ $b$ 间的路径,都可拆分为 $a$ 到 $lca$ 的路径和 $b$ 到 $lca$ 的路径

采用贪心策略, $low[x][i]$ 表示从 $x$ 点出发向上选择不超过 $2^i$ 条链可抵达的深度最浅的点。这时对于每一个询问可将询问的两个端点修改为利用贪心策略跳到的深度大于 $lca$ 且深度最小的节点,并记录下答案,这个过程可以用倍增完成。注意特判端点即 $lca$ 的情况。

然后出现两种情况。若修改后的两个端点出现在同一条给定链上,答案为原答案 $+1$ ,否则答案为原答案 $+2$ 。问题模型转换为,每次询问一个点对是否出现在同一条给定链上。记录下 $dfs$ 序,在深搜过程中利用树状数组统计即可。

时间复杂度 $O(nlogn)$ 

 

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<vector>
  5 #define LL long long
  6 using namespace std;
  7 const int N=2e5+5;
  8 const int inf=0x3f3f3f3f;
  9 int n,m,Q,cnt,val,x,y,ind;
 10 int deep[N],in[N],out[N],last[N];
 11 int first[N],ans[N],tr[N];
 12 int fa[N][20],low[N][20];
 13 bool ok[N];
 14 vector<int> a[N],b[N];
 15 struct edge{int to,next;}e[N];
 16 struct chain{int x,y,t;}c[N],q[N];
 17 int read()
 18 {
 19     int x=0,f=1;char c=getchar();
 20     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
 21     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
 22     return x*f;
 23 }
 24 void ins(int u,int v){e[++cnt]=(edge){v,first[u]};first[u]=cnt;}
 25 void dfs(int x)
 26 {
 27     in[x]=++ind;
 28     for(int i=1;(1<<i)<=deep[x];i++)
 29         fa[x][i]=fa[fa[x][i-1]][i-1];
 30     for(int i=first[x];i;i=e[i].next)
 31     {
 32         deep[e[i].to]=deep[x]+1;
 33         dfs(e[i].to);
 34     }
 35     out[x]=ind;
 36 }
 37 int lca(int x,int y)
 38 {
 39     if(deep[x]<deep[y])swap(x,y);
 40     int d=deep[x]-deep[y];
 41     for(int i=0;(1<<i)<=d;i++)
 42         if((1<<i)&d)x=fa[x][i];
 43     if(x==y)return x;
 44     for(int i=17;i>=0;i--)
 45         if((1<<i)<=deep[x]&&fa[x][i]!=fa[y][i])
 46             x=fa[x][i],y=fa[y][i];
 47     return fa[x][0];
 48 }
 49 void dfslow(int x)
 50 {
 51     for(int i=first[x];i;i=e[i].next)
 52     {
 53         int to=e[i].to;dfslow(to);
 54         if(deep[low[to][0]]<deep[low[x][0]])
 55             low[x][0]=low[to][0];
 56     }
 57 }
 58 int find(int x,int t)
 59 {
 60     if(deep[low[x][17]]>deep[t]){val=-inf;return -1;}
 61     if(x==t){val=-1;return 0;}
 62     val=0;
 63     for(int i=17;i>=0;i--)
 64         if(deep[low[x][i]]>deep[t])
 65             x=low[x][i],val|=(1<<i);
 66     return x;
 67 }
 68 int lowbit(int x){return x&(-x);}
 69 void add(int x,int v){for(;x<=n;x+=lowbit(x))tr[x]+=v;}
 70 int query(int x){int ans=0;for(;x;x-=lowbit(x))ans+=tr[x];return ans;}
 71 void work(int x)
 72 {
 73     for(int sz=b[x].size(),i=0;i<sz;i++)
 74     {
 75         int t=b[x][i];
 76         last[t]=query(out[q[t].y])-query(in[q[t].y]-1);
 77     }
 78     for(int sz=a[x].size(),i=0;i<sz;i++)add(in[a[x][i]],1);
 79     for(int i=first[x];i;i=e[i].next)work(e[i].to);
 80     for(int sz=b[x].size(),i=0;i<sz;i++)
 81     {
 82         int t=b[x][i];
 83         if(query(out[q[t].y])-query(in[q[t].y]-1)!=last[t])ok[t]=true;
 84     }
 85 }
 86 int main()
 87 {
 88     n=read();
 89     for(int i=2;i<=n;i++)
 90         fa[i][0]=read(),ins(fa[i][0],i);
 91     dfs(1);
 92     for(int i=1;i<=n;i++)low[i][0]=i;
 93     m=read();
 94     for(int i=1;i<=m;i++)
 95     {
 96         c[i].x=read();c[i].y=read();
 97         c[i].t=lca(c[i].x,c[i].y);
 98         if(deep[c[i].t]<deep[low[c[i].x][0]])
 99             low[c[i].x][0]=c[i].t;
100         if(deep[c[i].t]<deep[low[c[i].y][0]])
101             low[c[i].y][0]=c[i].t;
102         a[c[i].x].push_back(c[i].y);
103         a[c[i].y].push_back(c[i].x);
104     }
105     dfslow(1);
106     for(int t=1;t<=n;t++)
107         for(int i=1;i<=17;i++)
108             low[t][i]=low[low[t][i-1]][i-1];
109     Q=read();
110     for(int i=1;i<=Q;i++)
111     {
112         q[i].x=read();q[i].y=read();
113         q[i].t=lca(q[i].x,q[i].y);
114         ans[i]=2;
115         x=find(q[i].x,q[i].t);ans[i]+=val;
116         y=find(q[i].y,q[i].t);ans[i]+=val;
117         if(x>0&&y>0)
118         {
119             q[i].x=x;q[i].y=y;
120             b[x].push_back(i);
121         }
122     }
123     work(1);
124     for(int i=1;i<=Q;i++)
125         if(ok[i])ans[i]--;
126     for(int i=1;i<=Q;i++)
127         printf("%d\n",ans[i]<0?-1:ans[i]);
128     return 0;
129 }
View Code

 

转载于:https://www.cnblogs.com/zsnuo/p/9057523.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值