zoukankan      html  css  js  c++  java
  • HDU 5118 GRE Words Once More!

    题目链接:HDU-5118

    题意:给定一个有向无环图,每条边有一个权值。标定一些特定节点为“特殊节点”。从节点1出发到某“特殊节点”结束的路径,称为一个“GRE单词”。单词由路径上的权值组成。给定一组查询(k_i),问由给定的图产生的所有单词,按字典序排序后第(k_i)个单词的长度(即由多少条边组成)。

    思路:首先这道题最吓人之处在于(k_i<=10^{8}),单纯的扫一遍所有可能出现的单词会超时。这时我们发现,输出时只要求输出单词长度,而不要求输出单词内容。由于是DAG,每个节点不会连回到祖宗节点。我们定义vis[i]为从节点i出发可以找到以“特殊节点”结尾的路径的数量。则可以得到递推关系:(vis[u]=sum_{V}{vis[v]})。同样的道理,我们记录第一次访问每个节点时,产生的所有以“特殊节点”结尾的路径。那么每个节点的子节点其实只需要遍历一次。之后访问时,直接加上之前的结果就可以了。

    如果题解说的不是很明白,建议直接看代码,很容易看懂。

    网上的一些题解说需要手动dfs,不过本人并没有手动也没有爆栈。建议谨慎地尝试。

     1 #include"bits/stdc++.h"
     2 using namespace std;
     3 typedef long long LL;
     4 
     5 // ans[i]为字典序第i的单词
     6 // vis[i]为从节点i出发能找到以“特殊节点”结尾的路径的数量
     7 // firstVis[i]为从节点i出发找到的"所有以“特殊节点”结尾的路径的深度"在ans中存储的起始位置
     8 // firstVisDep[i]为第一次访问i时的深度
     9 const int MAXN=100010;
    10 const int MAXM=100000010;
    11 struct Edge
    12 {
    13     int u,v,w;
    14     Edge(int uu,int vv,int ww)
    15     {
    16         u=uu,v=vv,w=ww;
    17     }
    18     bool operator < (Edge x)
    19     {
    20         return w < x.w;
    21     }
    22 };
    23 vector<Edge> G[MAXN];
    24 int s[MAXN];  
    25 int n,m,q;
    26 int sum;
    27 int ans[MAXM],vis[MAXN],firstVis[MAXN],firstVisDep[MAXN];
    28 void addEdge(int u,int v,int w)
    29 {
    30     G[u].push_back(Edge(u,v,w));
    31 }
    32 void dfs(int u,int dep)
    33 {
    34     if(sum>=100000000) return;
    35     if(vis[u]!=-1)
    36     {
    37         for(int i=1;i<=vis[u];i++)
    38         {
    39             if(sum>=100000000) return;
    40             ans[++sum]=ans[firstVis[u]+i]+dep-firstVisDep[u];
    41         }
    42         return ;
    43     }
    44     firstVis[u]=sum;
    45     firstVisDep[u]=dep;
    46     if(s[u]) ans[++sum]=dep;
    47     for(unsigned int i=0;i<G[u].size();i++)
    48     {
    49         int v=G[u][i].v;
    50         dfs(v,dep+1);
    51     }
    52     vis[u]=sum-firstVis[u];
    53 }
    54 int main()
    55 {
    56 #ifdef LOCAL
    57     freopen("in.txt","r",stdin);
    58     // freopen("out.txt","w",stdout);
    59 #endif
    60     int t;
    61     scanf("%d",&t);
    62     for(int tt=1;tt<=t;tt++)
    63     {
    64         scanf("%d%d%d",&n,&m,&q);
    65         for(int i=1;i<=n;i++) G[i].clear();
    66         s[1]=0;
    67         for(int i=2;i<=n;i++) scanf("%d",&s[i]);
    68         for(int i=1;i<=m;i++) 
    69         {
    70             int u,v,w;
    71             scanf("%d%d%d",&u,&v,&w);
    72             addEdge(u,v,w);
    73         }
    74         for(int i=1;i<=n;i++) sort(G[i].begin(),G[i].end());
    75         memset(vis,-1,sizeof(vis));
    76         sum=0;
    77         dfs(1,0);
    78         printf("Case #%d:
    ",tt);
    79         for(int i=1;i<=q;i++) 
    80         {
    81             int x;
    82             scanf("%d",&x);
    83             if(x<=sum) printf("%d
    ",ans[x]);
    84             else printf("-1
    ");
    85         }
    86     }
    87     return 0;
    88 }
  • 相关阅读:
    Codeforces 101487E
    算法笔记--2-sat
    算法笔记--图的存储之链式前向星
    算法笔记--强连通分量分解
    Uva 11995 I Can Guess the Data Structure!
    算法笔记--米勒-罗宾素数测试
    HDU 5183 Negative and Positive (NP)
    算法笔记--快读(输入外挂)模板
    POJ 3258 River Hopscotch
    HDU 2289 Cup
  • 原文地址:https://www.cnblogs.com/zarth/p/6561084.html
Copyright © 2011-2022 走看看