zoukankan      html  css  js  c++  java
  • CSUST 1011 神秘群岛 (Dijkstra+LCA)

    神秘群岛
     

    Description

     

    小J继续着周游世界的旅程,这次他来到了一个神奇的群岛。这片群岛有n个岛屿,同时这些岛屿被标上了1-n的编号。

    每个岛屿上面都有神奇的传送门,传送门可以把小J从当前的岛屿u传送到指定的岛屿v上面,同时在对应的岛屿v上也有一个与之相对应的传送门,可以使用这个传送门从岛屿v回到岛屿u。

    细心的小J发现了传送门有一些小字“这些岛屿上面总的有2*(n-1)个传送门,将这些岛屿连接起来,一个传送门最多只能使用一次,即只能帮助你从岛屿u到岛屿v,使用一次之后传送门就会消失。”

    同时,小J也发现了使用一次传送门之后能够得到一定的金币,但使用一对相对应的传送门能得到的金币的数量是不相同的,即从岛屿u到岛屿v能得到的金币和从岛屿v到岛屿u能得到的金币是不同的。

    现在小J想知道如果他一开始在岛屿x上,想要借助传送门前往岛屿y,途中最多能收集多少金币。(到达岛屿y之后小J还可以继续前往别的岛屿,只要保证他最后能回到岛屿y就行)。

    Input

     

    输入:第一行一个T,代表数据组数。

    第二行一个n,表示岛屿的数量。

    接下来n-1行,每行有4个数,u,v,c1,c2,表示使用从岛屿u到岛屿v的传送门能得到c1个金币,使用从岛屿v到岛屿u的传送门能得到c2个金币。

    接下来一行一个q。代表询问次数。

    接下来q行,每行两个数x和y,代表小L现在在岛屿x上,想前往岛屿y。

    数据范围T<=10

    n<=100000

    1<=u,v<=n,1<=c1,c2<=100000

    q<=100000

    1<x,y<=n

    Output

     

    输出:输出q行

    对于每次询问,输出正确答案。

    Sample Input 1 

    1
    5
    1 2 5 10
    3 5 25 3
    4 2 15 12
    3 2 6 7
    2
    1 5
    4 3

    Sample Output 1

    64
    65

    思路:
    寒假耗费了大量时光,到现在才学会LCA,真是菜得罪有应得。
    虽然当时看出来,这是一个树结构,但是对他也没有什么好的办法来解决,所以只好事后来补题。
    先用两遍Dijkstra,求出根节点到每个节点的最短路,以及其反向边的最短路。然后,利用LCA,求出每次询问的两个节点的最近公共父节点。
    设LCA为t,询问的节点是x,y。那么t到x的最短路,就是根节点到x的最短路,减去根节点到t的最短路。求反向边的最短路,是因为x到y的路径,有一段是向上的,有一段是向下的。
    答案就是所有路径的总和,减去x到y的路径的反向边的权值总和
    代码:
    #include<iostream>
    #include<algorithm>
    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<queue>
    using namespace std;
    typedef long long ll;
    const int maxn = 1e5+6;
    const ll inf = 2e11;
    vector<int>u[maxn];
    int bin[30];
    int fa[maxn][30];
    vector<ll>w[maxn],wt[maxn];
    ll dis1[maxn],dis2[maxn];
    int deep[maxn];
    ll sum;
    struct node
    {
        int x;
        ll dis;
        bool operator<(const node x)const
        {
            return x.dis<dis;
        }
    };
    bool vis[maxn];
    
    void get_bin()
    {
        for(int i=0;i<20;i++){
            bin[i]=(1<<i);
        }
    }
    
    void build()
    {
        int n;
        scanf("%d",&n);
        int x,y;
        ll z1,z2;
        for(int i=1;i<=n-1;i++){
            scanf("%d%d%lld%lld",&x,&y,&z1,&z2);
            u[x].push_back(y);
            w[x].push_back(z1);
            wt[x].push_back(z2);
            u[y].push_back(x);
            wt[y].push_back(z1);
            w[y].push_back(z2);
            sum+=z1+z2;
        }
    }
    
    void bfs()
    {
        memset(vis,0,sizeof(vis));
        queue<int>q;
        q.push(1);
        deep[1]=1;
        int cur;
        vis[1]=true;
        while(!q.empty()){
            cur=q.front();q.pop();
            vis[cur]=true;
            for(int i=1;i<20;i++){
                if(bin[i]>deep[cur]){break;}
                fa[cur][i]=fa[fa[cur][i-1]][i-1];
            }
            int siz=u[cur].size();
            for(int i=0;i<siz;i++){
                int t=u[cur][i];
                if(vis[t]){continue;}
                fa[t][0]=cur;
                deep[t]=deep[cur]+1;
                q.push(t);
            }
        }
    }
    void Dijkstra1()
    {
        memset(vis,0,sizeof(vis));
        priority_queue<node>q;
        q.push(node{1,0ll});
        node exa;
        dis1[1]=0;
        int cur,t;
        while(!q.empty()){
            exa=q.top();q.pop();
            t=exa.x;
            if(vis[t]){continue;}
            vis[t]=0;
            int siz=u[t].size();
            for(int i=0;i<siz;i++){
                if(dis1[u[t][i]]>dis1[t]+w[t][i]){
                    dis1[u[t][i]]=dis1[t]+w[t][i];
                    q.push(node{u[t][i],dis1[u[t][i]]});
                }
            }
        }
    }
    void Dijkstra2()
    {
        memset(vis,0,sizeof(vis));
        priority_queue<node>q;
        q.push(node{1,0ll});
        node exa;
        dis2[1]=0;
        int cur,t;
        while(!q.empty()){
            exa=q.top();q.pop();
            t=exa.x;
            if(vis[t]){continue;}
            vis[t]=0;
            int siz=u[t].size();
            for(int i=0;i<siz;i++){
                if(dis2[u[t][i]]>dis2[t]+wt[t][i]){
                    dis2[u[t][i]]=dis2[t]+wt[t][i];
                    q.push(node{u[t][i],dis2[u[t][i]]});
                }
            }
        }
    }
    int lca(int x,int y)
    {
        if(deep[x]<deep[y]){swap(x,y);}
        int t=deep[x]-deep[y];
        for(int i=0;i<=20;i++){
            if(bin[i]&t){x=fa[x][i];}
        }
        for(int i=20;i>=0;i--){
            if(fa[x][i]!=fa[y][i]){
                x=fa[x][i];
                y=fa[y][i];
            }
        }
        if(x==y){return x;}
        else return fa[x][0];
    }
    void solve()
    {
        bfs();
        Dijkstra1();
        Dijkstra2();
        int q;
        scanf("%d",&q);
        int x,y;
        ll ans;
        for(int i=1;i<=q;i++){
            scanf("%d%d",&x,&y);
            int t=lca(x,y);
            ans=sum-(dis1[x]-dis1[t])-(dis2[y]-dis2[t]);
            printf("%lld
    ",ans);
        }
    }
    void init()
    {
        for(int i=0;i<maxn;i++){
            wt[i].clear();
            w[i].clear();
            u[i].clear();
            dis1[i]=inf;
            dis2[i]=inf;
        }
        memset(deep,0,sizeof(deep));
        memset(fa,0,sizeof(fa));
        sum=0;
    }
    
    int main()
    {
        int T;
        scanf("%d",&T);
        get_bin();
        while(T--){
            init();
            build();
            solve();
        }
        return 0;
    }
    

      第一发没有清空fa数组,WA了。

      其实我不是很理解,为什么要清空fa数组,因为fa在一租新的数据中,要用到的都有自然更新。。。

     
  • 相关阅读:
    E230的Android历程
    Web.config
    程序集和命名空间 转载
    CSS 得到图片 为什么是负 值。
    JQUERY中 GET与POST方法的区别 Request.QueryString Request.Form区别
    JS中scrollLeft(right,top,bottom)的用法和特点
    ashx是什么文件
    自己写了个 logO图片上 显示问题则CSS样式。CSS可是真强大啊。
    jquery + ashx DropDownList 二级
    CSS与超链接<a><A>的恩怨情仇。。。
  • 原文地址:https://www.cnblogs.com/ZGQblogs/p/9511428.html
Copyright © 2011-2022 走看看