• [IOI2013]wombats


    题目链接

    博客园链接

    主要是想记录一下Maze 2D这种模型。

    给一张 (n imes m) 的网格图,长成长条状,网格上的边有边权。人每次只能向上向下向右走,不能向左走。(q) 次询问,每次查从一个点走到另一个点的最短路。询问之间可能会穿插 (t) 次修改边权。

    法一:DP

    单次询问显然可以 (n imes m) 地DP:设 (f(i,j)) 表示从起点走到 ((i,j)) 的最短路。(g(i,j) = f(i,j-1) + lft(i,j))。((lft,rgt,up,dn) 均为边权)然后有:

    [f(i,j) = min_k(g(k,j) + dis((k,j),(i,j)) ]

    一列一列地考虑即可。复杂度:(O(t + nmq))

    法二:线段树套Floyd

    因为 (m) 非常小,我们可以用线段树维护 (L...R) 列中 (dis(i,j))。显然可以类似 Floyd 算法那样合并。这样的话复杂度就是 (O((t+q)log n imes m^3))。可以通过Maze 2D这道题。

    法三:决策单调性优化Floyd

    如果 (m) 不是那么小,我们每次 Floyd 的时候无法 (m^3) 地计算 (dis(i,j))。不过我们发现,((i,j)) 的决策点一定比 ((i,j-1))((i-1,j)) 靠后(假设边权均为正)。于是可以用决策单调性优化Floyd。复杂度:(O((t+q)log n imes m^2))。优化空间后可以通过[IOI2013]wombats这题。

    (IOI2013wombats的代码)

    const int block = 20;
    int n, m;
    int rgt[NN][N], dn[NN][N];
    int g[N][N], h[N];
    struct node {
    	int f[N][N];
    	int l, r;
    	node() { memset(f, 0x3f, sizeof(f)); l = r = 0; }
    	node(int L, int R) {
    		l = L, r = R;
    		memset(f, 0x3f, sizeof(f));
    		memset(h, 0, sizeof(h));
    		for (int p = 1; p <= m; ++p) {
    			for (int sum = 0, j = p; j; --j, sum += rgt[L][j])	f[p][j] = sum;
    			for (int sum = 0, j = p; j <= m; sum += rgt[L][j], ++j)	f[p][j] = sum;
    			for (int i = L + 1; i <= R + 1; ++i) {
    				for (int j = 1; j <= m; ++j)	h[j] = f[p][j] + dn[i - 1][j], f[p][j] = inf;
    				for (int mn = h[1], sum = 0, j = 1; j <= m; sum += rgt[i][j], ++j, MIN(mn, h[j] - sum))
    					MIN(f[p][j], mn + sum);
    				for (int mn = h[m], sum = 0, j = m; j; --j, sum += rgt[i][j], MIN(mn, h[j] - sum))
    					MIN(f[p][j], mn + sum);
    			}
    		}
    	}
    }nd[NNN];
    inline node operator +(const node &a, const node &b) {
    	node res;
    	memset(g, 0, sizeof(g));
    	for (int i = m; i; --i) {
    		for (int j = 1; j <= m; ++j) {
    			int d = j == 1 ? 1 : g[i][j - 1];
    			int u = i == m ? m : g[i + 1][j];
    			for (int k = d; k <= u; ++k) {
    				if (res.f[i][j] > a.f[i][k] + b.f[k][j]) {
    					res.f[i][j] = a.f[i][k] + b.f[k][j];
    					g[i][j] = k;
    				}
    			}
    		}
    	}
    	res.l = a.l; res.r = b.r;
    	return res;
    }
    
    int ls[NNN], rs[NNN], ttot, root;
    inline void pushup(int cur) {
    	nd[cur] = nd[ls[cur]] + nd[rs[cur]];
    }
    void build(int L, int R, int &cur) {
    	cur = ++ttot;
    	if (R - L + 1 <= block)	return nd[cur] = node(L, R), void();
    	int mid = (L + R) >> 1;
    	build(L, mid, ls[cur]); build(mid + 1, R, rs[cur]);
    	pushup(cur);
    }
    void modify(int L, int R, int pos, int cur) {
    	if (R - L + 1 <= block)	return nd[cur] = node(L, R), void();
    	int mid = (L + R) >> 1;
    	if (pos <= mid)	modify(L, mid, pos, ls[cur]);
    	else	modify(mid + 1, R, pos, rs[cur]);
    	pushup(cur);
    }
    
  • 相关阅读:
    ExtJs中ComboBox使用之技巧
    Ethernet帧结构
    Sqlite修改表
    Solr系列:Linux下部署Solr
    Ethernet帧的接收流程
    使用SQLite作为Quartz.Net的Job Store
    Quartz.Net的一个Bug
    获取程序集的Public key token
    SQLite数据类型
    shell取出多列文件中某一列重复的数据
  • 原文地址:https://www.cnblogs.com/JiaZP/p/13787363.html
Copyright © 2020-2023  润新知