您的位置:首页 > 其它

【NOIP2013】【ygylca】 货车运输带权并查集

2014-08-21 18:28 253 查看
Description

A 国有 n 座城市,编号从 1 到 n,城市之间有 m 条双向道路。每一条道路对车辆都有重量限制,简称限重。现在有 q 辆货车在运输货物,司机们想知道每辆车在不超过车辆限重的情况下,最多能运多重的货物。

Input

第一行有两个用一个空格隔开的整数 n,m,表示 A 国有 n 座城市和 m 条道路。

接下来 m 行每行 3 个整数 x、y、z,每两个整数之间用一个空格隔开,表示从 x 号城市到 y 号城市有一条限重为 z 的道路。注意:x 不等于 y,两座城市之间可能有多条道路。

接下来一行有一个整数 q,表示有 q 辆货车需要运货。

接下来 q 行,每行两个整数 x、y,之间用一个空格隔开,表示一辆货车需要从 x 城市运输货物到 y 城市,注意:x 不等于 y。

Output

输出共有 q 行,每行一个整数,表示对于每一辆货车,它的最大载重是多少。如果货车不能到达目的地,输出-1。

Sample Input

4 3 1 2 4 2 3 3 3 1 1 3 1 3 1 4 1 3

Sample Output

3 -1 3

HINT

对于 30%的数据,0 < n < 1,000,0 < m < 10,000,0 < q < 1,000;

对于 60%的数据,0 < n < 1,000,0 < m < 50,000,0 < q < 1,000;

对于 100%的数据,0 < n < 10,000,0 < m < 50,000,0 < q < 30,000,0 ≤ z ≤ 100,000。

题解: lca就不细说了。

①用并查集维护一个数组fc[i],表示i点到其当前祖先路线中的最长路径,find函数压缩路径时顺便维护。

②利用tarjan并查集求每个询问的lca,在lca处加一个链表,每个询问a->b都有a到lca中的最长路,b到lca的最长路,取大值作为询问的解。

代码:

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define N 100100
#define min(a,b) ((a)<(b)?(a):(b))

typedef struct KSD
{
    int u,v,next,l;
}ksd;ksd e
,eq
,el
;
int head
,headq
,headl
;
void add(int note,int u,int v,int l){e[note].u=u;e[note].v=v;e[note].l=l;e[note].next=head[u];head[u]=note;}
void addq(int note,int u,int v){eq[note].u=u;eq[note].v=v;eq[note].next=headq[u];headq[u]=note;}
void addl(int note,int u,int v){el[note].u=u;el[note].v=v;el[note].next=headl[u];headl[u]=note;}

int n,m,p;
int f
,fa
,fl
,back
,visit
;//祖先,父亲,到祖先距离,到父亲距离,是否遍历完子节点
int used
;//已经dfs过 

void init()
{
     int i;
     for(i=1;i<=n;i++)f[i]=i;
     memset(head,-1,sizeof(head));
     memset(headq,-1,sizeof(headq));
     memset(headl,-1,sizeof(headl));
     memset(eq,-1,sizeof(eq));
     memset(fl,0x3f,sizeof(fl));
}

int find(int x)
{
     int t=f[x];
     if(f[x]==x)return x;
     f[x]=find(f[x]);
     fl[x]=min(fl[x],fl[t]);
     return f[x];
}
void tjlca(int x,int p)//tarjanlca
{
     int i,t,v,fv,tt;
     used[x]=1;
     for(t=head[x];t!=-1;t=e[t].next)
     {
         v=e[t].v;
         if(v==p)continue;
         fa[v]=x;
         back[v]=e[t].l;
         tjlca(v,x);
     }
     for(t=headq[x];t!=-1;t=eq[t].next)
     {
         v=eq[t].v;
         if(visit[v]==1)
         {
             fv=find(v);
             tt=(t+1)/2*2;
             eq[tt].l=fl[v];
             addl(tt,fv,x);
         }
     }
     for(t=headl[x];t!=-1;t=el[t].next)
     {
         v=el[t].v;
         find(v);
         eq[t].l=min(eq[t].l,fl[v]);
     }
     f[x]=p;
     fl[x]=back[x];
     visit[x]=1;
}

ksd road
;
int cnt;
int cmp(const void *a,const void*b){return (*(ksd *)b).l-(*(ksd *)a).l;}

void Kruskal()
{
     int i,j,k;
     int fa,fb;
     for(i=1;i<=m;i++)scanf("%d%d%d",&road[i].u,&road[i].v,&road[i].l);
     qsort(road+1,m,sizeof(road[1]),cmp);
     for(i=1;i<=m;i++)
     {
         fa=find(road[i].u);
         fb=find(road[i].v);
         if(fa!=fb)
         {
             cnt++;
             f[fa]=fb;
             add(cnt*2-1,road[i].u,road[i].v,road[i].l);
             add(cnt*2,road[i].v,road[i].u,road[i].l);
         }
         if(cnt+1==n)return ;
     }
}

int main()
{
     //freopen("test.txt","r",stdin);
     int i,j,k;
     int a,b,c;
     scanf("%d%d",&n,&m);
     init();
     Kruskal();
     for(i=1;i<=n;i++)f[i]=i;
     scanf("%d",&p);
     for(i=1;i<=p;i++)
     {
         scanf("%d%d",&a,&b);
         addq(i*2-1,a,b);
         addq(i*2,b,a);
     }
     for(i=1;i<=n;i++)
     {
         if(used[i]==0)
         {
             tjlca(i,i);
             memset(visit,0,sizeof(visit));
         }
     }
     for(i=1;i<=p;i++)printf("%d\n",eq[i*2].l);
     return 0;
}


复制去Google翻译翻译结果
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: