[CF864F]Cities Excursions

题目大意:
  一个$n(n\le3000)$个点的有向图,$q(q\le4\times10^5)$组询问,每次询问$s_i,t_i$之间是否存在一条字典序最小的路径(可以重复经过不为$t_i$的结点)。若存在,求出该路径上经过的第$k_i$个结点。

思路:
  将原图的边反向。考虑根据$t_i$对所有询问进行分组。对于$t_i$相同的询问,在反向图中DFS,求出每个结点到$t_i$的最小字典序路径中的下一个结点是多少,这可以转化为一个树形结构。若$s_i$与$t_i$不连通,则说明路径不存在;若$s_i$的第$2^{\lfloor\log_2n\rfloor+1}$级祖先存在,则说明存在环。询问第$k_i$个结点可以树上倍增。

 1 #include<cstdio>
 2 #include<cctype>
 3 #include<cstring>
 4 #include<forward_list>
 5 inline int getint() {
 6     register char ch;
 7     while(!isdigit(ch=getchar()));
 8     register int x=ch^'0';
 9     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
10     return x;
11 }
12 constexpr int N=3001,Q=4e5,logN=13;
13 std::forward_list<int> e[N];
14 struct Query {
15     int s,k,id;
16 };
17 std::forward_list<Query> q[N];
18 int ans[Q],anc[N][logN];
19 inline int lg2(const float &x) {
20     return ((unsigned&)x>>23&255)-127;
21 }
22 void dfs(const int &x,const int &par,const int &s) {
23     anc[x][0]=par;
24     for(auto &y:e[x]) {
25         if(y==s||(anc[y][0]&&anc[y][0]<=x)) continue;
26         dfs(y,x,s);
27     }
28 }
29 int main() {
30     const int n=getint(),m=getint(),cnt_q=getint(),lim=lg2(n)+1;
31     for(register int i=0;i<m;i++) {
32         const int u=getint(),v=getint();
33         e[v].push_front(u);
34     }
35     for(register int i=0;i<cnt_q;i++) {
36         const int s=getint(),t=getint(),k=getint();
37         q[t].push_front({s,k-1,i});
38     }
39     for(register int i=1;i<=n;i++) {
40         if(q[i].empty()) continue;
41         memset(anc,0,sizeof anc);
42         dfs(i,0,i);
43         for(register int j=1;j<=lim;j++) {
44             for(register int i=1;i<=n;i++) {
45                 anc[i][j]=anc[anc[i][j-1]][j-1];
46             }
47         }
48         for(register auto &j:q[i]) {
49             if(!anc[j.s][0]||anc[j.s][lim]) continue;
50             for(register int i=0;j.k;j.k>>=1,i++) {
51                 if(j.k&1) j.s=anc[j.s][i];
52             }
53             ans[j.id]=j.s;
54         }
55     }
56     for(register int i=0;i<cnt_q;i++) {
57         printf("%d\n",ans[i]?:-1);
58     }
59     return 0;
60 }

 

posted @ 2018-05-22 13:15  skylee03  阅读(123)  评论(0编辑  收藏  举报