欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

战争 I(最短路+离线算法)

程序员文章站 2022-05-27 20:03:11
...

题目描述
某年,白国和委国之间的战争爆发了!

然而,在委国指挥官委兆的眼里,白国人不堪一击。现在他手上有一张白国的地图,发现白国有 n 个据点,m 条无向道路,他们有各自的长度。于是他决定按一定顺序破坏白国的一些据点,使得所有连接这些据点与其他据点的道路无法通行。同时,为了更有效率的攻城略地,也为了满足委兆的成就感,他有时还想知道当前某两个据点间的最短路径长。请编程满足他的要求。

输入
第一行两个正整数 n,m。

接下来 m 行,每行有三个数 a,b,v表示一条连接 a,b的无向边。

接下来一行一个正整数 q 。

接下来 q 行,每行是两个数 “ 1 a ” 或是三个数 “ 2 a b ” ,含义如题面所述。

输出
对于每个“ 2 a b ” 操作,输出对应的结果。
若两点不连通,输出−1 。

样例输入
4 4
1 2 6
3 4 1
1 3 4
1 4 9
3
2 1 4
1 3
2 1 4

样例输出
5
9

提示
对于 100%的数据 n≤200,m≤n∗(n−1)/2,q≤2×104,v≤1000保证所有的操作合法。

思路
将所有问题离线运算,在记录问题时,先锁定被标记的点,对每个问题,从最后计算到最前,并倒序解锁标记点,每次解锁对全图进行更新

代码实现

#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=205;
const int M=50005;
const int INF=0x3f3f3f3f;
const ll LINF=0x3f3f3f3f3f3f3f3f;
const ull sed=31;
const ll mod=10000019;
const double eps=1e-5;
const double PI=acos(-1.0);
typedef pair<int,int>P;
typedef pair<double,double>Pd;
          
template<class T>void read(T &x)
{
    x=0;int f=0;char ch=getchar();
    while(ch<'0'||ch>'9') {f|=(ch=='-');ch=getchar();}
    while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    x=f?-x:x;
    return;
}
  
ll mp[N][N];
int n,m,q;
P qus[M];
bool vis[N];
vector<ll>ans;
  
int main()
{
      
    //freopen("a.txt","r",stdin);
    read(n);read(m);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)  
            if(i!=j) mp[i][j]=LINF;
    for(int i=0;i<m;i++)
    {
        int u,v;ll w;
        read(u);read(v);read(w);
        mp[u][v]=min(mp[u][v],w);
        mp[v][u]=mp[u][v];
    }
    read(q);
    for(int i=1;i<=q;i++)
    {
        int op,a,b;
        qus[i]=P(0,0);
        read(op);
        if(op==1) 
        {
            read(a);
            if(!vis[a]) qus[i]=P(a,0);
            vis[a]=true;
        }
        else
        {
            read(a);read(b);
            qus[i]=P(a,b);
        }
    }
    for(int k=1;k<=n;k++)
        for(int i=1;i<=n;i++)
            for(int j=1;j<=n;j++)
                if(!vis[i] && !vis[j] && !vis[k]) 
                    mp[i][j]=min(mp[i][j],mp[i][k]+mp[k][j]);
    for(int len=q;len;len--)
    {
        if(!qus[len].first && !qus[len].second) continue;
        if(qus[len].second)
        {
            int u=qus[len].first,v=qus[len].second;
            if(vis[u] || vis[v]) ans.push_back(LINF);
            else ans.push_back(mp[u][v]);
        }
        else
        {
            int u=qus[len].first;
            vis[u]=false;
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    if(!vis[i] && !vis[j]) 
                    {
                        mp[i][u]=min(mp[i][u],mp[i][j]+mp[j][u]);
                        mp[u][i]=min(mp[u][i],mp[u][j]+mp[j][i]);
                    }
            for(int i=1;i<=n;i++)
                for(int j=1;j<=n;j++)
                    if(!vis[i] && !vis[j])
                        mp[i][j]=min(mp[i][j],mp[i][u]+mp[u][j]); 
        }
    }
    for(int i=ans.size()-1;i>=0;i--)
    {
        if(ans[i]==LINF) puts("-1");
        else printf("%lld\n",ans[i]);
    }
    return 0;
}