zoukankan      html  css  js  c++  java
  • JZOJ 7377.欢乐豆

    \(\text{Problem}\)

    有一个有向完全图,所有的 \(u\)\(v\) 的边权为 \(a_u\)
    修改 \(m\) 此有向边边权,求最终图上两两点对的最短路之和
    \(1\le n \le 10^5,1\le m \le 3000,1\le a_u \le 10^6\)

    \(\text{Solution}\)

    好题
    如果没有修改边,那么 \(u\) 到任意一点的最短路为 \(a_u\)
    有修改边,注意到 \(m\) 相对 \(n\) 很小,也就是说涉及的点很少,不妨称其为特殊点
    显然特殊点个数最多为 \(O(m)\) 的,且特殊边也是 \(O(m)\)
    考虑把特殊边连起来的点看成一个连通块(也就是视特殊边为无向边,把特殊点连起来)
    我们导出这些特殊点构成的图,就是很多连通块的组成的图
    这样再考虑两两点对间的最短路
    无非分为特殊点到块内和到块外
    \(1.\) 特殊点到块外就是特殊点到普通点和特殊点到不在此连通块内的特殊点
    \(2.\) 特殊点到块内一定是特殊点到特殊点的最短路
    先考虑 \(①\)
    逐个考虑块内的点 \(x\) 到块外所有点的最短路
    显然是此块内点 \(x\) 到此块内其它点 \(y\) 再到外面
    \(dis(x,y)+a_y\) 的最小值
    所以 \(①\) 贡献的最短路和为 \((n-cnt) \cdot min\)
    再考虑 \(②\)
    通过某种手段求出块内全源最短路,将这些 \(dis\) 加起来即可
    有特殊边,有普通边,普通边是形如 \(a_u\) 的只和此端点有关
    枚举起点,用线段树维护 \(dis\)
    特殊边单点修改松弛,特殊边没被影响过的点用普通边松弛,这些点分散在多个区间,线段树上区间修改即可
    然后就完成了,确实有点麻烦,但思路很清晰

    \(\text{Code}\)

    #include <cstdio>
    #include <iostream>
    #include <vector>
    #include <algorithm>
    #define ls (p << 1)
    #define rs (ls | 1)
    #define re register
    using namespace std;
    typedef long long LL; 
    
    const int N = 1e5 + 5;
    const LL INF = 1e15;
    int n, m, a[N], id[N], Q[N], cnt, tot, Tot, bz[N], h[N], H[N], color;
    LL dis[N];
    vector<int> d[N];
    struct edge{int to, nxt, w;}e[N];
    inline void add_edge(int x, int y, int z){e[++tot] = edge{y, h[x], z}, h[x] = tot;}
    struct Edge{int to, nxt;}E[N];
    inline void add_Edge(int x, int y){E[++Tot] = Edge{y, H[x]}, H[x] = Tot;}
    struct node{int x; LL s;}b[N];
    inline node Min(node a, node b){return (a.s <= b.s ? a : b);}
    inline bool cmp(node a, node b){return a.s < b.s;}
    
    inline void read(int &x)
    {
    	x = 0; char ch = getchar(); int f = 1;
    	for(; !isdigit(ch); f = (ch == '-' ? -1 : f), ch = getchar());
    	for(; isdigit(ch); x = (x<<3) + (x<<1) + (ch^48), ch = getchar());
    	x *= f;
    }
    
    void dfs(int x)
    {
    	bz[x] = color, Q[++cnt] = x;
    	for(re int i = H[x]; i; i = E[i].nxt) if (!bz[E[i].to]) dfs(E[i].to);
    }
    
    LL tag[N >> 1], Mn[N >> 1]; int Mp[N >> 1];
    inline void pushup(int p)
    {
    	if (Mn[ls] <= Mn[rs]) Mn[p] = Mn[ls], Mp[p] = Mp[ls];
    	else Mn[p] = Mn[rs], Mp[p] = Mp[rs];
    }
    void build(int p, int l, int r)
    {
    	tag[p] = Mn[p] = INF;
    	if (l == r) return void(Mp[p] = l);
    	int mid = l + r >> 1;
    	build(ls, l, mid), build(rs, mid + 1, r), pushup(p);
    }
    inline void pushdown(int p)
    {
    	if (tag[p] == INF) return;
    	if (Mn[ls] != INF + 1) Mn[ls] = min(Mn[ls], tag[p]), tag[ls] = min(tag[ls], tag[p]);
    	if (Mn[rs] != INF + 1) Mn[rs] = min(Mn[rs], tag[p]), tag[rs] = min(tag[rs], tag[p]);
    	tag[p] = INF;
    }
    void modify(int p, int l, int r, int tl, int tr, LL v)
    {
    	if (tl > r || tr < l || v >= tag[p]) return;
    	if (tl <= l && r <= tr) 
    	{
    		if (Mn[p] != INF + 1) Mn[p] = min(Mn[p], v), tag[p] = min(tag[p], v);
    		return;
    	}
    	pushdown(p);
    	int mid = l + r >> 1;
    	if (tl <= mid) modify(ls, l, mid, tl, tr, v);
    	if (tr > mid) modify(rs, mid + 1, r, tl, tr, v);
    	pushup(p);
    }
    void pushflag(int p, int l, int r, int x)
    {
    	if (l == r) return void(Mn[p] = tag[p] = INF + 1);
    	pushdown(p);
    	int mid = l + r >> 1;
    	if (x <= mid) pushflag(ls, l, mid, x);
    	else pushflag(rs, mid + 1, r, x);
    	pushup(p);
    }
    
    void solve()
    {
    	LL ans = 0, lst = 0;
    	for(re int i = 1; i <= n; i++)
    	if (!bz[i])
    	{
    		cnt = 0, ++color, dfs(i), sort(Q + 1, Q + cnt + 1);
    		int r = 1;
    		while (bz[b[r].x] == color && r <= n) ++r;
    		for(re int l = 1; l <= cnt; l++) id[Q[l]] = l;
    		for(re int l = 1; l <= cnt; l++)
    		{
    			build(1, 1, cnt), modify(1, 1, cnt, l, l, 0);
    			for(re int j = 1; j <= cnt; j++)
    			{
    				node now = node{Mp[1], Mn[1]};
    				for(re int k = h[Q[now.x]]; k; k = e[k].nxt) modify(1, 1, cnt, id[e[k].to], id[e[k].to], now.s + e[k].w);
    				if (d[Q[now.x]].size())
    				{
    					modify(1, 1, cnt, 1, id[d[Q[now.x]][0]] - 1, now.s + a[Q[now.x]]);
    					for(re int k = 1; k < d[Q[now.x]].size(); k++)
    						modify(1, 1, cnt, id[d[Q[now.x]][k - 1]] + 1, id[d[Q[now.x]][k]] - 1, now.s + a[Q[now.x]]);
    					modify(1, 1, cnt, id[d[Q[now.x]][d[Q[now.x]].size() - 1]] + 1, cnt, now.s + a[Q[now.x]]);
    				}
    				else modify(1, 1, cnt, 1, cnt, now.s + a[Q[now.x]]);
    				if (r <= n) modify(1, 1, cnt, 1, cnt, now.s + a[Q[now.x]] + b[r].s);
    				ans += (dis[now.x] = now.s), pushflag(1, 1, cnt, now.x);
    			}
    			LL mi = INF;
    			for(re int j = 1; j <= cnt; j++) mi = min(mi, dis[j] + a[Q[j]]);
    			ans += mi * (n - cnt);
    		}
    	}
    	printf("%lld\n", ans);
    }
    
    int main()
    {
    	freopen("happybean.in", "r", stdin), freopen("happybean.out", "w", stdout);
    	read(n), read(m);
    	for(re int i = 1; i <= n; i++) read(a[i]), b[i].x = i, b[i].s = a[i]; sort(b + 1, b + n + 1, cmp);
    	for(re int i = 1, x, y, z; i <= m; i++)
    		read(x), read(y), read(z), add_edge(x, y, z), d[x].push_back(y), add_Edge(x, y), add_Edge(y, x);
    	for(re int i = 1; i <= n; i++) sort(d[i].begin(), d[i].end());
    	solve();
    }
    
  • 相关阅读:
    [LeetCode]2. Add Two Numbers链表相加
    Integration between Dynamics 365 and Dynamics 365 Finance and Operation
    向视图列添加自定义图标和提示信息 -- PowerApps / Dynamics365
    Update the Power Apps portals solution
    Migrate portal configuration
    Use variable to setup related components visible
    Loyalty management on Retail of Dynamic 365
    Modern Fluent UI controls in Power Apps
    Change screen size and orientation of a canvas app in Power App
    Communication Plan for Power Platform
  • 原文地址:https://www.cnblogs.com/leiyuanze/p/15547726.html
Copyright © 2011-2022 走看看