NOI2018:归程

题目大意:题面
\(\;\;\;\;\;\;\)给定无向图,每条边有长度和高度,多次询问从某个点pi出发到1号点的最短路,并给出参数qi,规定所有能从pi出发仅通过高度>qi的边到达的点视为可以不耗费代价地到达。

具体思路:\(\;\;\)Kruskal重构树(据说这个算法大家都熟悉,但我怎么好像不知道啊,溜了溜了)
\(\;\;\;\;\;\;\)发现可以把边按高度从大到小加入图中(像Kruskal求最小生成树那样),然后图就会变成一堆连通块,然后当一条边联通了两个连通块时,就在重构树上新建一个节点,把两个连通块当成新点的儿子
\(\;\;\;\;\;\;\)维护好重构树的每个子树上离1最近点的最近距离,求答案时只要从s向上倍增至联通的边刚刚能露出水面时,当前子树的答案就是这个询问的答案
\(\;\;\;\;\;\;\)复杂度为\(O(nlogn)\)

据说SPFA被卡了,真是大快人心,dij多好啊
AC代码

#include
#include
#include
#include
#include
using namespace std;

int n,m,T,q,x,y,z,zz,k,s,v0,p0,lastans,v,p,nowans;
const int N=1000000,INF=1e9;
int dis[N],vis[N],f[N],fa[N],ans[N],out[N],FA[N][20],H[N];
vector son[N];
struct link
{
    int top,fi[N],ne[N],la[N],to[N],l[N],h[N];
    inline void clear()
    {
        top=0,memset(fi,0,sizeof fi),memset(ne,0,sizeof ne),memset(la,0,sizeof la),memset(to,0,sizeof to),memset(l,0,sizeof l),memset(h,0,sizeof h);
    }
    inline void add(int x,int y,int z,int H)
    {
        top++,to[top]=y,l[top]=z,h[top]=H;
        if(fi[x]==0)fi[x]=top;else ne[la[x]]=top;
        la[x]=top;
    }
}L;
struct node
{
    int id,dis;
    bool operator < (const node &a) const {return a.dis < dis;}
};
priority_queue que;
inline void DIJKSTRA()
{
    for(int i=1;i<=n;i++)dis[i]=INF,vis[i]=0;
    dis[1]=0;while(!que.empty())que.pop();
    node tmp;
    tmp.id=1;tmp.dis=0;que.push(tmp);
    while (!que.empty()) 
    {
        int now=que.top().id;
        que.pop();
        if (vis[now]) continue;
        vis[now]=true;
        for (int i=L.fi[now];i;i=L.ne[i]) 
        {
            if (!vis[L.to[i]]&&dis[L.to[i]]>dis[now]+L.l[i]) 
            {
                dis[L.to[i]]=dis[now]+L.l[i];
                tmp.id=L.to[i];tmp.dis=dis[L.to[i]];
                que.push(tmp);
            }
        }
    }
}
struct E{int x,y,l,h;}e[N];
inline bool cmp(E a,E b){return a.h>b.h;}
inline int ASK(int x){if(fa[x]==x)return x;else return fa[x]=ASK(fa[x]);}
void dfs(int x)
{
    for(int i=1;i<=19;i++)FA[x][i]=FA[FA[x][i-1]][i-1];
    for(int i=0;i=0;i--)if(H[FA[now][i]]>p)now=FA[now][i];
            lastans=ans[now];
            printf("%d\n",lastans);
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/Orange-User/p/9362738.html

你可能感兴趣的:(NOI2018:归程)