zoukankan      html  css  js  c++  java
  • 【BZOJ 4456】【UOJ #184】【ZJOI 2016】旅行者

    http://www.lydsy.com/JudgeOnline/problem.php?id=4456

    http://uoj.ac/problem/184

    参考(抄)的晨爷的题解(代码)

    对矩形进行分治。

    每次对一个分治中的矩形,枚举中轴线上的点,依次做dijkstra,范围是该矩形内的点。

    处理出中轴线上的点到矩形内所有点的最短路,这样,两点在该矩形内的询问就可以用$dist+dist$更新了,意义是两点经过该中轴线的最短路。

    在把矩形劈成两半,把询问也分成两半,递归分治。

    因为两点间的最短路一定会穿过其中一个分治矩形的中轴线,所以这么做是正确的。

    时间复杂度是$O(nsqrt{n}log^2n)$,不理解少一个$log$的复杂度的做法。

    #include<queue>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    const int N = 20003;
    const int Qnum = 500003;
    int in() {
    	int k = 0, fh = 1; char c = getchar();
    	for(; c < '0' || c > '9'; c = getchar())
    		if (c == '-') fh = -1;
    	for(; c >= '0' && c <= '9'; c = getchar())
    		k = (k << 3) + (k << 1) + c - '0';
    	return k * fh;
    }
    
    bool inq[N];
    struct node {int nxt, to, w;} E[N << 2];
    struct query {int x0, y0, x1, y1, id;} Q[Qnum], sta[Qnum];
    int q, tot = 0, cnt = 0, point[N], n, m, ans[Qnum], dist[N];
    
    void ins(int u, int v, int w) {E[++cnt] = (node) {point[u], v, w}; point[u] = cnt;}
    int get(int x, int y) {return (x - 1) * m + y;}
    
    struct Point {
    	int id, dist;
    	Point(int _id = 0, int _dist = 0) : id(_id), dist(_dist) {}
    	bool operator < (const Point &A) const {
    		return dist > A.dist;
    	}
    };
    priority_queue <Point> qu;
    void dijkstra(int S, int x0, int y0, int x1, int y1) {
    	int u;
    	for(int i = x0; i <= x1; ++i)
    		for(int j = y0; j <= y1; ++j) {
    			u = get(i, j);
    			dist[u] = 0x7fffffff; inq[u] = false;
    		}
    	dist[S] = 0;
    	Point x;
    	qu.push(Point(S, 0));
    	while (!qu.empty()) {
    		x = qu.top();
    		qu.pop();
    		if (inq[x.id]) continue;
    		inq[x.id] = true;
    		for(int i = point[x.id]; i; i = E[i].nxt)
    			if (x.dist + E[i].w < dist[E[i].to]) {
    				dist[E[i].to] = x.dist + E[i].w;
    				qu.push(Point(E[i].to, dist[E[i].to]));
    			}
    	}
    }
    
    void cdq(int x0, int y0, int x1, int y1, int Ql, int Qr) {
    	if (Ql > Qr) return;
    	if (x1 - x0 > y1 - y0) {
    		int mid = (x1 + x0) >> 1, po, tmp_l, tmp_r;
    		for(int i = y0; i <= y1; ++i) {
    			po = get(mid, i);
    			dijkstra(po, x0, y0, x1, y1);
    			for(int j = Ql; j <= Qr; ++j)
    				ans[Q[j].id] = min(ans[Q[j].id], dist[get(Q[j].x0, Q[j].y0)] + dist[get(Q[j].x1, Q[j].y1)]);
    		}
    		
    		tmp_l = Ql - 1; tmp_r = Qr + 1;
    		for(int i = Ql; i <= Qr; ++i)
    			if (Q[i].x0 < mid && Q[i].x1 < mid) sta[++tmp_l] = Q[i];
    			else if (Q[i].x0 > mid && Q[i].x1 > mid) sta[--tmp_r] = Q[i];
    		for(int i = Ql; i <= tmp_l; ++i) Q[i] = sta[i];
    		for(int i = tmp_r; i <= Qr; ++i) Q[i] = sta[i];
    		
    		cdq(x0, y0, mid - 1, y1, Ql, tmp_l);
    		cdq(mid + 1, y0, x1, y1, tmp_r, Qr);
    	} else {
    		int mid = (y0 + y1) >> 1, po, tmp_l, tmp_r;
    		for(int i = x0; i <= x1; ++i) {
    			po = get(i, mid);
    			dijkstra(po, x0, y0, x1, y1);
    			for(int j = Ql; j <= Qr; ++j)
    				ans[Q[j].id] = min(ans[Q[j].id], dist[get(Q[j].x0, Q[j].y0)] + dist[get(Q[j].x1, Q[j].y1)]);
    		}
    		
    		tmp_l = Ql - 1; tmp_r = Qr + 1;
    		for(int i = Ql; i <= Qr; ++i)
    			if (Q[i].y0 < mid && Q[i].y1 < mid) sta[++tmp_l] = Q[i];
    			else if (Q[i].y0 > mid && Q[i].y1 > mid) sta[--tmp_r] = Q[i];
    		for(int i = Ql; i <= tmp_l; ++i) Q[i] = sta[i];
    		for(int i = tmp_r; i <= Qr; ++i) Q[i] = sta[i];
    		
    		cdq(x0, y0, x1, mid - 1, Ql, tmp_l);
    		cdq(x0, mid + 1, x1, y1, tmp_r, Qr);
    	}
    }
    
    int main() {
    	n = in(); m = in();
    	int len, Point;
    	for(int i = 1; i <= n; ++i)
    		for(int j = 1; j < m; ++j) {
    			len = in();
    			Point = get(i, j);
    			ins(Point, Point + 1, len);
    			ins(Point + 1, Point, len);
    		}
    	for(int i = 1; i < n; ++i)
    		for(int j = 1; j <= m; ++j) {
    			len = in();
    			Point = get(i, j);
    			ins(Point, Point + m, len);
    			ins(Point + m, Point, len);
    		}
    	
    	q = in();
    	int x0, y0, x1, y1;
    	memset(ans, 127, sizeof(int) * (q + 1));
    	for(int i = 1; i <= q; ++i) {
    		x0 = in(); y0 = in(); x1 = in(); y1 = in();
    		if (x0 == x1 && y0 == y1) {ans[i] = 0; continue;}
    		Q[++tot] = (query) {x0, y0, x1, y1, i};
    	}
    	
    	memset(inq, 1, sizeof(bool) * (n * m + 3));
    	cdq(1, 1, n, m, 1, tot);
    	
    	for(int i = 1; i <= q; ++i) printf("%d
    ", ans[i]);
    	return 0;
    }
    

    终于AC了

  • 相关阅读:
    dup/dup2函数
    read/write函数
    lseek函数
    流程控制
    vim普通模式
    vim实用技巧1
    python源代码解读
    python变量命名规则
    python之字符串2
    Docker系列文章
  • 原文地址:https://www.cnblogs.com/abclzr/p/5862592.html
Copyright © 2011-2022 走看看