ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【Noip模拟 20160929】花坛迷宫

2019-03-30 21:39:18  阅读:301  来源: 互联网

标签:dep Noip int 20160929 花坛 fa low LCA 500010


题目描述

圣玛格丽特学园的一角有一个巨大、如迷宫般的花坛。大约有一个人这么高的大型花坛,做成迷宫的形状,深受中世纪贵族的喜爱。维多利加的小屋就坐落在这迷宫花坛的深处。某一天早晨,久城同学要穿过这巨大的迷宫花坛,去探望感冒的维多利加。

整个迷宫可以用N个路口与M条连接两个不同路口的无向通道来描述。路口被标号为1到N,每条通道有各自的长度。整个迷宫一定是连通的,迷宫中可能存在若干个环路,但是,出于美观考虑,每个路口最多只会属于一个简单环路。例如,图1所示的迷宫是非常美观的,但图2则不符合我们的描述,因为3号路口同属于两个简单环。

你需要回答多个这样的询问:假如久城处在路口x,维多利加的小屋处在路口y,久城最短需要走多少距离才能到达小屋?

输入数据

第一行2个整数N,M,表示迷宫花坛的路口数和通道数;

接下来M行,每行3个整数x,y,z,描述一条连接路口x与路口y,长度为z的通道;

再接下来1行包含一个整数Q,表示询问数量;

之后Q行,每行2个整数x,y,描述一个询问。

输出数据

对于每个询问输出一行一个整数,表示最短距离。

样例输入

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

样例输出

3
2

数据范围

对于30%30%的数据,N≤100N≤100;

另有30%30%的数据,保证N=MN=M;

对于100%100%的数据,1≤N≤100000,0≤Q≤200000,1≤x,y≤N,1≤z≤10001≤N≤100000,0≤Q≤200000,1≤x,y≤N,1≤z≤1000。

由于传题人比较懒,hack数据只需满足是一个仙人掌

题目分析

大家好,我是老A。我又回来了,我很不爽。我们维护这个图的强连通分量,因为SPFA会跑飞,我们用Tarjan算法,然后求LCA即可,这一题NOI第三题水平。我们可以用可持久化分块,也可以倍增树剖ST表。要是你想要用堆优化线段树,那你滚吧。

参考代码

我知道你们就等着看我的代码,那我只好给你看了。

#include<bits/stdc++.h>
using namespace std;
int n,m;
inline int abs(int x) {return x>0?x:-x;}
int head[500010], next[500010], to[500010], tot=0; 
int scc=0, dfn[500010],low[500010], DFN=0; 
vector<int> s[500010],son[500010];
int st[500010],stn=0;
int fa[500010][19],dep[500010],size[500010];
map<int,int> d[500010], f[500010];
int D[500010];
inline void add(int u, int v, int tw) {
    ++tot;
    next[tot]=head[u];
    head[u]=tot;
    to[tot]=v;
    if(f[u].find(v)==f[u].end()) 
        f[u][v]=tw;
    else f[u][v]=min(f[u][v], tw); 
}
O2 inline int getdep(int x) {
    if(fa[x][0]==0) dep[x]=1;
    if(dep[x]) return dep[x]; 
    return dep[x]=getdep(fa[x][0])+1;
}
inline void init() {
    memset(dep, 0, sizeof(dep)); 
    for (int i=1; i<=18; ++i) {
        for (int j=1; j<=scc; ++j) fa[j][i] = fa[fa[j][i-1]][i-1];
        for (int j=n+1; j<=n*2; ++j) fa[j][i] = fa[fa[j][i-1]][i-1];
    }
    for (int i=1; i<=scc; ++i) getdep(i);
    for (int i=n+1; i<=n*2; ++i) getdep(i);
} 
int tx, ty;
O2 inline int lca(int x,int y)   {  
    if(dep[x]<dep[y]) swap(x,y);
    for(int j=18; j>=0; --j)  
        if(dep[fa[x][j]]>=dep[y]) x=fa[x][j]; 
    if(x==y) return x;
    for (int j=18; j>=0; --j) 
        if(fa[x][j] != fa[y][j]) x=fa[x][j], y=fa[y][j];
    tx=x,ty=y;
    return fa[x][0];
}
O2 inline void tarjan(int x) {
    low[x]=dfn[x]=++DFN;
    st[++stn]=x;
    for (int i=head[x]; i; i=next[i]) {
        if(dfn[to[i]] != 0) {
            low[x] = min(low[x], dfn[to[i]]);
        }else{
            tarjan(to[i]);
            if(low[to[i]]==dfn[x]){
                ++scc;
                son[x].push_back(scc);
                s[scc].push_back(x); 
                fa[scc][0]=n+x; 
                int t;
                do {
                    t=st[stn--];
                    s[scc].push_back(t); 
                    fa[n+t][0]=scc; 
                } while(t != to[i]); 
            }
            low[x] = min(low[x], low[to[i]]);
        }
    }
}
O2 inline void pre(int x) {
    vector<int>::iterator it,_it;  
    stn=0;
    for (int i=0,sz=s[x].size(); i<sz; ++i) st[++stn]=s[x][i];
    st[++stn]=s[x][0];
    for (int i=1; i<stn; ++i) {
        size[x] += f[st[i]][st[i+1]];
        if(i!=stn-1) d[x][st[i+1]]=d[x][st[i]]+f[st[i]][st[i+1]]; 
    }int s1=2, t=stn-1;
    while(s1<=t) {
        if(D[st[s1-1]]+f[st[s1-1]][st[s1]]<D[st[t+1]]+f[st[t+1]][st[t]]){            
            D[st[s1]]=D[st[s1-1]]+f[st[s1-1]][st[s1]];
            ++s1;
        } else {
            D[st[t]]=D[st[t+1]]+f[st[t+1]][st[t]]; 
            --t;
        }
    }
    for (it=s[x].begin(),it++; it!=s[x].end(); ++it)  
        for (_it=son[*it].begin(); _it!=son[*it].end(); ++_it) pre(*_it);
}

char chh; int xx;
O2 inline int read() {
    chh=getchar();xx=0;
    while(!isdigit(chh)) chh=getchar();
    while(isdigit(chh)) {
        xx=(xx<<3)+(xx<<1)+chh-'0';
        chh=getchar();
    }
    return xx;
}
          
O2 int main() {
    n=read(), m=read();
    for (int i=1, u, v, tw; i<=m; ++i) {
         u=read(), v=read(), tw=read();
         add(u, v, tw);
         add(v, u, tw); 
    }
    tarjan(1); init(); 
    vector<int>::iterator it;  
    for(it=son[1].begin();it!=son[1].end();it++)  
        pre(*it);  
    int T=read();
    while(T--) {
        int x, y;
        x=read(), y=read();
        int LCA=lca(n+x,n+y);
        if(LCA>n) printf("%d\n", D[x]+D[y]-2*D[LCA-n]); 
        else {
            int ans = D[x]+D[y]-D[tx-n]-D[ty-n];
            int tmp = abs(d[LCA][tx-n]-d[LCA][ty-n]);
            ans+=min(tmp, size[LCA]-tmp);
            printf("%d\n", ans);
        }
    }
    return 0;
}

代码分析

Tarjan不解释,我们用STL来记录这几个点,第一次知道map可以这样迭代。最后我们用vector跑LCA,输出的时候判断一下就好了。

PS:PS内容在下一期。。。

 

标签:dep,Noip,int,20160929,花坛,fa,low,LCA,500010
来源: https://www.cnblogs.com/aserrrre/p/10629139.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有