• 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在一租新的数据中,要用到的都有自然更新。。。

     
  • 相关阅读:
    js string format All In One
    CSS water wave effect All In One
    Github PR 时合并多次提交的 git commits All In One
    js auto selector dom by providing id All In One
    JSS All In One
    python 中将fastq文件保存为字典
    python 中统计fasta文件中每条序列的长度
    c语言中利用do while循环语句限制用户的输入范围
    python中记录程序运行时间
    c语言中的do while循环语句
  • 原文地址:https://www.cnblogs.com/ZGQblogs/p/9511428.html
Copyright © 2020-2023  润新知