The Shortest Statement,LCA

You are given a weighed undirected connected graph, consisting of nn vertices and mmedges.

You should answer qq queries, the ii-th query is to find the shortest distance between vertices uiui and vivi.

Input

The first line contains two integers nn and m (1≤n,m≤105,m−n≤20)m (1≤n,m≤105,m−n≤20) — the number of vertices and edges in the graph.

Next mm lines contain the edges: the ii-th edge is a triple of integers vi,ui,di (1≤ui,vi≤n,1≤di≤109,ui≠vi)vi,ui,di (1≤ui,vi≤n,1≤di≤109,ui≠vi). This triple means that there is an edge between vertices uiui and vivi of weight didi. It is guaranteed that graph contains no self-loops and multiple edges.

The next line contains a single integer q (1≤q≤105)q (1≤q≤105) — the number of queries.

Each of the next qq lines contains two integers uiui and vi (1≤ui,vi≤n)vi (1≤ui,vi≤n) — descriptions of the queries.

Pay attention to the restriction m−n ≤ 20m−n ≤ 20.

Output

Print qq lines.

The ii-th line should contain the answer to the ii-th query — the shortest distance between vertices uiui and vivi.

Examples

Input

3 3
1 2 3
2 3 1
3 1 5
3
1 2
1 3
2 3

Output

3
4
1

Input

8 13
1 2 4
2 3 6
3 4 1
4 5 12
5 6 3
6 7 8
7 8 7
1 4 1
1 8 3
2 6 9
2 7 1
4 6 3
6 8 2
8
1 5
1 7
2 3
2 8
3 7
3 4
6 8
7 8

Output

7
5
6
7
7
1
2
7

 

 

代码:

#include<bits/stdc++.h>
#define MAXN 100005
using namespace std;
int n,m,dd[MAXN],head[MAXN],par[MAXN][20],head1[MAXN],tot1,tot;
long long dis[MAXN];
struct edge
{
    int u,v,nxt;
    long long w;
}edg[MAXN<<1],e[MAXN],edg1[MAXN<<1];
inline void addedg(int u,int v,long long w)
{
    edg[tot].v = v;
    edg[tot].w = w;
    edg[tot].nxt = head[u];
    head[u] = tot++;
}
inline void addedg1(int u,int v,long long w)
{
    edg1[tot1].v = v;
    edg1[tot1].w = w;
    edg1[tot1].nxt = head1[u];
    head1[u] = tot1++;
}
vector<int> ve;
int pre[MAXN],cnt,st[50];
int find(int x)
{
    return x == pre[x]?x:pre[x] = find(pre[x]);
}
inline bool merge(int x,int y)
{
    int zx = find(x),zy = find(y);
    if(zx == zy)
    {
        st[cnt++] = x,st[cnt++] = y;
        return false;
    }
    else
    {
        pre[zx] = zy;
        return true;
    }
}
void dfs(int k,int fa,int dep,long long w)
{
    dd[k] = dep,dis[k] = w;
    if(k == 1)
        for(int i = 19;i >= 0;--i)
            par[k][i] = k;
    else
    {
        par[k][0] = fa;
        for(int i = 1;i <= 19;++i)
            par[k][i] = par[par[k][i-1]][i-1];
    }
    for(int i = head[k];i != -1;i = edg[i].nxt)
        if(edg[i].v != fa)
            dfs(edg[i].v,k,dep+1,w+edg[i].w);
}
inline int jump(int u,int d)
{
    for(int i = 19;i >= 0;--i)
        if((1<<i)&d)
            u = par[u][i];
    return u;
}
inline int LCA(int u,int v)
{
    if(dd[u] < dd[v])
        swap(u,v);
    u = jump(u,dd[u]-dd[v]);
    if(u == v)
        return u;
    for(int i = 19;i >= 0;--i)
    {
        if(par[u][i] != par[v][i])
        {
            u = par[u][i];
            v = par[v][i];
        }
    }
    return par[u][0];
}
struct node
{
    int id;
    long long w;
    node(){}
    node(int id,long long w):id(id),w(w){}
    friend bool operator<(node n1,node n2)
    {
        return n2.w < n1.w;
    }
}nod;
priority_queue<node> qu;
long long dis1[50][MAXN];
inline void dijkstra(int s,int k)
{
    while(!qu.empty())
        qu.pop();
    dis1[k][s] = 0;
    qu.push(node(s,0));
    while(!qu.empty())
    {
        nod = qu.top();
        qu.pop();
        if(dis1[k][nod.id] != nod.w)
            continue;
        for(int i = head1[nod.id];i != -1;i = edg1[i].nxt)
        {
            int v = edg1[i].v;
            if(dis1[k][nod.id] + edg1[i].w < dis1[k][v])
            {
                dis1[k][v] = dis1[k][nod.id] + edg1[i].w;
                qu.push(node(v,dis1[k][v]));
            }
        }
    }
}
inline void init()
{
    memset(head,-1,4*n+4);
    memset(head1,-1,4*n+4);
    memset(dis1,0x3f,sizeof(dis1));
    tot = cnt = tot1 = 0;
    ve.clear();
    for(int i = 1;i <= n;++i)
        pre[i] = i;
}


int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        init();
        for(int i = 1;i <= m;++i)
        {
            scanf("%d%d%lld",&e[i].u,&e[i].v,&e[i].w);
            addedg1(e[i].u,e[i].v,e[i].w);
            addedg1(e[i].v,e[i].u,e[i].w);
            if(merge(e[i].u,e[i].v))
            {
                addedg(e[i].u,e[i].v,e[i].w);
                addedg(e[i].v,e[i].u,e[i].w);
            }
        }
        sort(st,st+cnt);
        cnt = unique(st,st+cnt) - st;
        for(int i = 0;i < cnt;++i)
            dijkstra(st[i],i);
        dfs(1,1,1,0);
        int q,u,v;
        scanf("%d",&q);
        while(q--)
        {
            scanf("%d%d",&u,&v);
            long long ans = dis[u] + dis[v] - 2*dis[LCA(u,v)];
            for(int i = 0;i < cnt;++i)
                ans = min(ans,dis1[i][u] + dis1[i][v]);
            printf("%lld\n",ans);
        }
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用android studio 运行,下面是一个简单的文档,这个代码是一个demo 一、Activity的使用 1、SNActivity 框架最基本的activity,可调用$(SNManager)进行操作activity,具体用法请参考文档或代码 2、SNNavigationSlidingActivity 包含SNActivity的功能,继承于com.jeremyfeinstein.slidingmenu.lib.app.SlidingActivity 支持导航条和左滑视图的Activity 加载导航条: loadNavBar(int height,int background_color_id) loadNavBarResId(int height_id,int background_id) 加载左侧视图: /** * load left view * @param left_id left layout id * @param offset_value offset value * @param shadow_width_value shadow width value * @param shadow_drawable_id shadow drawable style * @param fade fade value */ loadLeft(int left_id, int offset_value, int shadow_width_value, int shadow_drawable_id, float fade) /** * load left view * @param left_id left layout id * @param offset_id offset id * @param shadow_width_id shadow width id * @param shadow_drawable_id shadow drawable id * @param fade fade value */ loadLeftResId(int left_id, int offset_id, int shadow_width_id, int shadow_drawable_id, float fade) 二、SNElement的使用 View的伪装对象,支持所有View的功能,详细功能可参考文档或代码 手动伪装:$.create $.id $.findView 注入伪装:$.setContent(view class or layout id,inject class); 获取原型:elem.toView(); 三、注入 1、视图注入 A、创建注入类,属性名称必须和layout中的id对应,如果不对应请加入标签@SNInjectView class DemoInject{ @SNInjectView(id=R.id.tvTest) public SNElement test; } B、实例化注入对象 DemoInject di=new DemoInject(); C、调用$.inject或者$.setContent注入 $.inject(di); D、注入成功后即可调用对象 String text=di.test.text(); 2、依赖注入 A、需要绑定注入对象,建议写到Application中的onCreate SNBindInjectManager.instance().bind(ITest.class, Test.class); B、与视图注入不同的是属性必须添加标签@SNIOC,注入的对象(Test)必须包含只有一个SNManager参数的构造函数,且必须实现注入者 public class Test implements ITest{ SNManager $; public Test(SNManager _$){ this.$=_$; }; } class DemoInject{ @SNIOC public ITest test; } C、调用$.inject或者$.setContent注入 同视图注入 D、注入成功后即可调用对象 di.test.xxx(); 四、fragment的使用 1、SNFragment 2、SNLazyFragment 五、控件的使用 1、SNFragmentScrollable 2、SNPercentLinearLayout、SNPercentRelativeLayout 3、SNScrollable 4、SNSlipNavigation 5、XList 6、slidingtab

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值