2022CCPC绵阳-E-一类图上DP优化

link:https://codeforces.com/gym/104065/problem/E
题意:\(n\) 个城市由 \(m\) 条边连成一张无向图,每个点所属连通块大小至少是2。接下来有 \(q\) 次危机,每次危机恰发生在一个城市 \(x\),需要所有在 \(x\) 城市的所有居民迁移到其他城市(之后可以迁移回来)。第 \(i\) 个城市有 \(a_i\) 人,每个人经过一条边需要花费 \(w(u,v)\) 的代价。已知接下来发生危机的城市,问所有危机发生后,所有人的总代价最小是多少?
\(1\leq n,m,q\leq 10^5\)


首先对每个人单独考虑,设 \(f_i\) 是初始在 \(i\) 号点的人经过所有危机需要的花费,则 \(ans=\sum f_i a_i\)
然后很明显危机发生在 \(x\) 处,\(x\) 的人只需要考虑迁移到某相邻结点\(y\) ,则花费为 \(w(x,y)+\) 剩下时间里 \(y\) 需要的花费,所以很明显 \(f\) 需要倒着计算。设 \(f(i,j)\) 表示\(i\) 号点在 \(j\) 时刻往后考虑需要的最小花费,则

\[f(i,j)=\left\{\begin{aligned}&f(i,j+1),b_j\neq i\\ &\min_{k\in N(i)}f(k,j+1)+w(i,k),b_j=i\end{aligned}\right. \]

乍一看是个 \(O(nq)\) 的DP,每个点从相邻结点转移过来。从这题也可以看出这类问题的通用解法:按度数分块

  • \(deg(x)\leq T\) 的点,暴力枚举邻域的点
  • \(deg(x)>T\) 的点,这样的点不超过 \(2m/T\) 个。对于这些点是千万不能暴力枚举邻域的,我们可以对每个大度点开一个 multiset,在计算每个小度点时,暴力更新大度点。
  • 缕清一下需要写的东西:
    • 小度点连着任何点都可以直接暴力更新
    • 大度点连着小度点,需要在小度点的multiset里直接获取最小值
    • 大度点连着大度点呢?因为不超过 \(2m/T\) 个,所以在建图的时候可以直接按度数排序,暴力枚举最大的几个点,暴力计算
  • 这样的复杂度:
    • 问到小度点的时候,\(O(T)\) 地求值,\(O(T\log n)\) 地更新大度点
    • 问到大度点的时候,\(O(\log n+2m/T)\) 地求值
    • 均摊复杂度\(O(\log n+T\log n+\frac{2m}{T})\),前面 \(O(\log n)\) 不动,后面 \(T=\sqrt{2m\log n}\) 时取得最小
    • 最终复杂度是 \(O(q\log n+q\sqrt{2m\log n})=O(q\sqrt{2m\log n})\)
  • 这里会发现,我们复杂度的优越性其实来自于两者之中,有一个带 \(\log\) 而另一个可以完全不带,如果处理两种点都有 \(\log n\) 的话其实会退化成 \(O(q\sqrt m \log n)\) ,这样对于 \(10^5\) 的数据基本是跑不过的(除非常数特别小)
  • 这题还可以对时间分治,去掉根号里的\(\log n\),不过那个方法可能没什么普适性
#include<bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define fastio ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N=1e5+5;
const int MOD=998244353;
const ll INF=0x3f3f3f3f3f3f3f3f;
int n,m,q,T,head[N],deg[N],b[N];
vector<vector<pii>> G;
ll a[N],f[N];
multiset<ll> S[N];

int main(){
    fastio;
    cin>>n>>m>>q;
    G=vector<vector<pii>>(n+1);
    T=sqrt(2*m*log(n+1));
    rep(i,1,n)cin>>a[i];
    rep(i,1,m){
        int u,v,w;cin>>u>>v>>w;
        deg[u]++;G[u].pb(mp(v,w));
        deg[v]++;G[v].pb(mp(u,w));
    }
    rep(i,1,q)cin>>b[i];
    rep(i,1,n)sort(G[i].begin(),G[i].end(),[](pii p1,pii p2){return deg[p1.first]>deg[p2.first];});
    rep(x,1,n)if(deg[x]>T)for(auto [v,w]:G[x])if(deg[v]<=T)S[x].insert(w);
    for(int tc=q;tc>=1;tc--){
        int x=b[tc];
        if(deg[x]<=T){
            for(auto [v,w]:G[x])if(deg[v]>T)S[v].erase(S[v].find(f[x]+w));
            f[x]=INF;
            for(auto [v,w]:G[x])f[x]=min(f[x],f[v]+w);
            for(auto [v,w]:G[x])if(deg[v]>T)S[v].insert(f[x]+w);
        }else{
            f[x]=*S[x].begin();
            for(auto [v,w]:G[x]){
                if(deg[v]<=T)break;
                f[x]=min(f[x],f[v]+w);
            }
        }
    }
    ll ans=0;
    rep(i,1,n)ans=(ans+f[i]%MOD*a[i]%MOD)%MOD;
    cout<<ans;
    return 0;
}
posted @ 2024-03-17 22:49  yoshinow2001  阅读(62)  评论(0编辑  收藏  举报