Terrorists UVALive

来源:互联网 发布:vba 数组赋值 编辑:程序博客网 时间:2024/06/01 13:04

题目大意:

给一张n个点,m条边的无向图。共有q个询问,每次询问u到v的最短路。

   n <= 100000 ,  n-1 <= m <= n + 50 , q <= 50000


思路:

注意到边的的数量,n和m非常接近,所以可以近似于一棵树,这样,我们先抛出一棵最小生成树出来,然后之后这样肯定会有多出来的边,然后我们把多出来的边的端点都存下来,这样就出来了一些除了树上的点之外的点,这样我们再把这些点跑一边dij,这样之后我们对于查询u,v时不就变成了最小生成树上的距离和枚举每一个树上之外的点的dij的最小值了么,至于树上的最小值,我们可以lca,rmq搞;


#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<queue>#include<cmath>using namespace std;#define fuck() cout<<"-----"<<endl#define INF 0x3f3f3f3fconst int maxed=100000+10;struct E{    int v,bef,val;}e[maxed*10][2];struct Node{    int u,val;    bool operator < (const Node& n1) const    {        return val>n1.val;    }};int n,m,q,ans,cnt,head[maxed][2],gen[maxed],dp[maxed],cost[maxed],l[100+10],d[100+10][maxed];int f[maxed][20];bool vis[maxed];int main(){    int slove1(int);    void add_(int,int,int,int);    void  slove2(int,int);    void slove3(int,int);    void slove4();    int slove5(int,int);    int N,kcase=0;    scanf("%d",&N);    while(N--){        cnt=0;        ans=1;        memset(head,-1,sizeof(head));        memset(vis,false,sizeof(vis));        scanf("%d%d%d",&n,&m,&q);        for(int i=1;i<=n;i++)            gen[i]=i;        int a,b,c;        for(int i=0;i<m;i++){            scanf("%d%d%d",&a,&b,&c);            add_(a,b,c,0);            add_(b,a,c,0);            int x=slove1(a),y=slove1(b);            if(x!=y){                add_(a,b,c,1);                add_(b,a,c,1);                gen[x]=y;            }            else{                if(!vis[a]){                    l[++cnt]=a;                    vis[a]=true;                }                if(!vis[b]){                    l[++cnt]=b;                    vis[b]=true;                }            }        }        //fuck();        memset(d,INF,sizeof(d));        for(int i=1;i<=cnt;i++)            slove2(l[i],i);        //fuck();        memset(vis,false,sizeof(vis));        memset(cost,0,sizeof(cost));        for(int i=1;i<=n;i++)            gen[i]=i;        slove3(1,1);        slove4();        printf("Case %d:\n",++kcase);        while(q--){            scanf("%d%d",&a,&b);            int w=slove5(a,b);            //cout<<w<<endl;            int answer=cost[a]+cost[b]-2*cost[w];            for(int i=1;i<=cnt;i++)                answer=min(answer,d[i][a]+d[i][b]);            printf("%d\n",answer);        }    }    return 0;}int slove1(int x){    if(x==gen[x])        return x;    return gen[x]=slove1(gen[x]);}void add_(int x,int y,int val,int cur){    e[ans][cur].v=y;    e[ans][cur].val=val;    e[ans][cur].bef=head[x][cur];    head[x][cur]=ans++;}void  slove2(int s,int cur){    d[cur][s]=0;    memset(vis,false,sizeof(vis));    queue<Node> pq;    pq.push((Node){s,0});    while(!pq.empty()){        //fuck();        Node no=pq.front();        pq.pop();        for(int i=head[no.u][0];i!=-1;i=e[i][0].bef){            int w=d[cur][no.u]+e[i][0].val;            if(d[cur][e[i][0].v]>w){                d[cur][e[i][0].v]=w;                pq.push((Node){e[i][0].v,w});            }        }    }}void slove3(int x,int dep){    vis[x]=true;    dp[x]=dep;    for(int i=head[x][1];i!=-1;i=e[i][1].bef)        if(!vis[e[i][1].v]){            gen[e[i][1].v]=x;            cost[e[i][1].v]=cost[x]+e[i][1].val;            slove3(e[i][1].v,dep+1);        }}void slove4(){    memset(f,-1,sizeof(f));    for(int i=1;i<=n;i++)        f[i][0]=gen[i];    int len=(int)log2(n);    for(int i=1;i<=len;i++)        for(int j=1;j<=n;j++){            int r=f[j][i-1];            if(r==-1)                continue;            f[j][i]=f[r][i-1];        }}int slove5(int x,int y){    if(dp[x]<dp[y])        swap(x,y);    int len=(int)log2(n);    for(int i=len;i>=0;i--){        int r=f[x][i];        if(r==-1||dp[r]<dp[y])            continue;        x=r;    }    if(x==y)        return x;    for(int i=len;i>=0;i--){        int r1=f[x][i],r2=f[y][i];        if(r1==r2)            continue;        x=r1;        y=r2;        //fuck();    }    //cout<<f[x][0]<<endl;    return f[x][0];}


原创粉丝点击