BZOJ 4144 Dijkstra+Kruskal+倍增LCA

来源:互联网 发布:上海知柚网络科技公司 编辑:程序博客网 时间:2024/05/28 19:24

思路:
先把所有的加油站 push进按weight排序的优先队列里
对于每个不是加油站的点 找到到它的点的最短路以及它来源的加油站
如果x和y有边 且x和y加油站的来源不一样 则它可以连边

跑一边Kruskal

倍增查一下 搞定了

(注意图可能不连通)

//By SiriusRen#include <queue>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;#define N 444444int n,s,m,Station[N],rec[N],cnt,f[N],fa[N][35],maxx[N][35],T;int q,xx,yy,zz,w[N],v[N],first[N],next[N],tot,vis[N],dis[N],deep[N];struct Node{    int from,now,weight;    Node(){}    Node(int x,int y,int z){        from=x,now=y,weight=z;    }}jy,node[N];priority_queue<Node>pq;bool operator < (Node a,Node b){    return a.weight>b.weight;}void add(int x,int y,int z){    w[tot]=z,v[tot]=y,next[tot]=first[x],first[x]=tot++;}void Dijkstra(){    while(!pq.empty()){        Node t=pq.top();pq.pop();        if(vis[t.now])continue;        vis[t.now]=1;        for(int i=first[t.now];~i;i=next[i])            if(dis[v[i]]>dis[t.now]+w[i]){                dis[v[i]]=dis[t.now]+w[i];                rec[v[i]]=t.from;                pq.push(Node(t.from,v[i],dis[v[i]]));            }    }}int W[N],V[N],NEXT[N],FIRST[N],TOT;void add2(int X,int Y,int Z){    W[TOT]=Z,V[TOT]=Y,NEXT[TOT]=FIRST[X],FIRST[X]=TOT++;}int find(int x){return x==f[x]?x:f[x]=find(f[x]);}void Kruskal(){    for(int i=1;i<=n;i++)f[i]=i;    sort(node+1,node+1+cnt);    for(int i=cnt;i;i--){        int fx=find(node[i].now),fy=find(node[i].from);        if(fx!=fy){            f[fx]=fy;            add2(node[i].now,node[i].from,node[i].weight);            add2(node[i].from,node[i].now,node[i].weight);        }    }}void dfs(int x,int father){    vis[x]=T;    for(int i=1;i<=29;i++){        fa[x][i]=fa[fa[x][i-1]][i-1];        maxx[x][i]=max(maxx[x][i-1],maxx[fa[x][i-1]][i-1]);    }    for(int i=FIRST[x];~i;i=NEXT[i])        if(V[i]!=father){            deep[V[i]]=deep[x]+1;            fa[V[i]][0]=x,maxx[V[i]][0]=W[i];            dfs(V[i],x);        }}int lca(int x,int y){    int ans=0;    if(deep[x]<deep[y])swap(x,y);    for(int i=29;~i;i--)        if(deep[x]-(1<<i)>=deep[y])            ans=max(ans,maxx[x][i]);x=fa[x][i];    if(x==y)return ans;    for(int i=29;~i;i--)        if(fa[x][i]!=fa[y][i]){            ans=max(ans,max(maxx[x][i],maxx[y][i]));            x=fa[x][i],y=fa[y][i];        }    return max(ans,max(maxx[x][0],maxx[y][0]));}int main(){    memset(FIRST,-1,sizeof(FIRST));    memset(first,-1,sizeof(first));    memset(dis,0x3f,sizeof(dis));    scanf("%d%d%d",&n,&s,&m);    for(int i=1;i<=s;i++){        scanf("%d",&xx);        dis[xx]=0,Station[xx]=1,rec[xx]=xx;        pq.push(Node(xx,xx,0));    }    for(int i=1;i<=m;i++){        scanf("%d%d%d",&xx,&yy,&zz);        add(xx,yy,zz),add(yy,xx,zz);    }    Dijkstra();    for(int i=1;i<=n;i++)        for(int j=first[i];~j;j=next[j])            if(rec[v[j]]!=rec[i]){                node[++cnt].from=rec[i],node[cnt].now=rec[v[j]];                node[cnt].weight=dis[i]+w[j]+dis[v[j]];            }    Kruskal(),memset(vis,0,sizeof(vis));    for(int i=1;i<=n;i++)        if(Station[i]&&!vis[i])            T++,dfs(i,-1);    scanf("%d",&q);    for(int i=1;i<=q;i++){        scanf("%d%d%d",&xx,&yy,&zz);        if(vis[xx]==vis[yy]&&lca(xx,yy)<=zz)puts("TAK");        else puts("NIE");    }}

这里写图片描述

0 0