• 【题解】 「NOI2019」弹跳 KDT优化建图+最短路+剪枝+卡空间 LOJ3159


    Legend

    (n (1 le n le 70000)) 个二维平面上的点,(m (1 le m le 150000)) 条集体边,每条集体边为从某个点向一个矩形所在的所有点连边。

    (1) 到所有点的最短路。

    时空限制:( extrm{2s/128MB})

    Editorial

    很容易让人想到 ( m{xxx}) 优化建图,发现非常无趣的是,二维线段树是两个 (log)。被卡啦!

    于是我们果断用 ( m{kdtree})!发现还是被卡空间啦!

    于是我们考虑不把边建出来,而是直接对整棵子树取 (min)

    ( m{kdtree}) 恰好是一棵平衡树,也可以维护全局最小值!

    所以你就可以很方便的写 ( m{Dijkstra}) 啦!

    复杂度?(O(m sqrt{n}))

    Code

    • ( m{kdtree}) 真的难写。

    • ( m{kdtree}) 不剪枝?( m{TLE}) 欢迎你。

    #include <bits/stdc++.h>
    
    #define debug(...) ;
    // fprintf(stderr ,__VA_ARGS__)
    #define __FILE(x)
    	freopen(#x".in" ,"r" ,stdin);
    	freopen(#x".out" ,"w" ,stdout)
    
    int read(){
    	char k = getchar(); int x = 0;
    	while(k < '0' || k > '9') k = getchar();
    	while(k >= '0' && k <= '9') x = x * 10 + k - '0' ,k = getchar();
    	return x;
    }
    
    inline void chkmin(int &x ,int y){x = std::min(x ,y);}
    inline void chkmax(int &x ,int y){x = std::max(x ,y);}
    
    const int MX = 2e5 + 233;
    struct point{
    	int x[2] ,w ,id;
    	point(int X ,int Y ,int W = 0 ,int ID = 0){x[0] = X ,x[1] = Y ,w = W ,id = ID;}
    	point(int a[2] ,int W = 0 ,int ID = 0){x[0] = a[0] ,x[1] = a[1] ,w = W ,id = ID;}
    	point(){x[0] = x[1] = id = 0 ,w = INT_MAX;}
    }P[MX];
    
    struct node{
    	int mn[2] ,mx[2] ,ch[2];
    	int del ,covmn ,mnval ,mnfr ,val ,alive;
    	int mxval;
    	point tp;
    };
    
    int D;
    bool operator <(point a ,point b){return a.x[D] < b.x[D];}
    
    int trans[MX] ,tkdt[MX];
    struct KDT{
    	#define lch tr[x].ch[0]
    	#define rch tr[x].ch[1]
    	node tr[MX] ;
    	int cnt ,rt ,D;
    	KDT(){
    		for(int i : {0 ,1}){
    			tr[0].mx[i] = INT_MIN;
    			tr[0].mn[i] = INT_MAX;
    		}
    		tr[0].covmn = tr[0].mnval = tr[0].val = INT_MAX;
    		tr[0].mnfr = tr[0].alive = false;
    		tr[0].del = true;
    		tr[0].mxval = INT_MIN;
    	}
    	void docovmn(int x ,int v){
    		if(!tr[x].del) chkmin(tr[x].val ,v);
    		if(tr[x].alive){
    			chkmin(tr[x].mnval ,v);
    			chkmin(tr[x].covmn ,v);
    			chkmin(tr[x].mxval ,v);
    		}
    	}
    	void _pushup(int x){
    
    		if(!tr[x].del){
    			tr[x].mnval = tr[x].val;
    			tr[x].mxval = tr[x].val;
    			tr[x].mnfr = x;
    		}
    		else{
    			tr[x].mnfr = 0 ,tr[x].mnval = INT_MAX;
    			tr[x].mxval = INT_MIN;
    		}
    
    		tr[x].alive = tr[lch].alive || tr[rch].alive || !tr[x].del;
    
    		for(int i : {0 ,1}){
    			tr[x].mn[i] = tr[x].mx[i] = tr[x].tp.x[i];
    			for(int j : {lch ,rch}){
    				chkmin(tr[x].mn[i] ,tr[j].mn[i]);
    				chkmax(tr[x].mx[i] ,tr[j].mx[i]);
    				chkmin(tr[x].mnval ,tr[j].mnval);
    				chkmax(tr[x].mxval ,tr[j].mxval);
    				if(tr[x].mnval == tr[j].mnval){
    					tr[x].mnfr = tr[j].mnfr;
    				}
    			}
    		}
    	}
    	void pushup(int x){
    
    		if(!tr[x].del){
    			tr[x].mnval = tr[x].val;
    			tr[x].mxval = tr[x].val;
    			tr[x].mnfr = x;
    		}
    		else{
    			tr[x].mnfr = 0 ,tr[x].mnval = INT_MAX;
    			tr[x].mxval = INT_MIN;
    		}
    		tr[x].alive = tr[lch].alive || tr[rch].alive || !tr[x].del;
    
    		for(int j : {lch ,rch}){
    			chkmin(tr[x].mnval ,tr[j].mnval);
    			chkmax(tr[x].mxval ,tr[j].mxval);
    			if(tr[x].mnval == tr[j].mnval){
    				tr[x].mnfr = tr[j].mnfr;
    			}
    		}
    	}
    	void pushdown(int x){
    		if(tr[x].covmn != INT_MAX){
    			if(lch) docovmn(lch ,tr[x].covmn);
    			if(rch) docovmn(rch ,tr[x].covmn);
    			tr[x].covmn = INT_MAX;
    		}
    	}
    	void outputinfo(int x){
    		debug("Info of vertex %d:
    " ,x);
    		debug("> val = %d ,mnval = %d ,mnvalfrom = %d
    " ,tr[x].val ,tr[x].mnval ,tr[x].mnfr);
    		debug("> point = (%d ,%d)
    " ,tr[x].tp.x[0] ,tr[x].tp.x[1]);
    	}
    	int build(int L ,int R ,int d = 1){
    		if(L > R) return 0;
    		int mid = (L + R) >> 1 ,x = mid;
    
    		D = d ,std::nth_element(P + L ,P + mid ,P + R + 1);
    		trans[mid] = P[mid].id;
    		tkdt[P[mid].id] = mid;
    		
    		tr[x].tp = P[mid];
    		tr[x].covmn = INT_MAX;
    		tr[x].val = tr[x].tp.w;
    
    		lch = build(L ,mid - 1 ,!d);
    		rch = build(mid + 1 ,R ,!d);
    		_pushup(x);
    		// outputinfo(x);
    		return x;
    	}
    	void buildtree(int L ,int R){rt = build(L ,R);}
    	bool inside(point A ,point B ,point C ,point D){
    		// check if AB is in CD
    		for(int i : {0 ,1}){
    			if(!(C.x[i] <= A.x[i] && B.x[i] <= D.x[i])){
    				return false;
    			}
    		}
    		return true;
    	}
    	bool outside(point A ,point B ,point C ,point D){
    		return B.x[0] < C.x[0] || A.x[0] > D.x[0] 
    			|| B.x[1] < C.x[1] || A.x[1] > D.x[1];
    	}
    	void upd(point A ,point B ,int x ,int v){
    		if(!x) return;
    		pushdown(x);
    		if(inside(tr[x].mn ,tr[x].mx ,A ,B)){return docovmn(x ,v);}
    		if(tr[x].mxval <= v || outside(tr[x].mn ,tr[x].mx ,A ,B) || !tr[x].alive){return;}
    		if(inside(tr[x].tp ,tr[x].tp ,A ,B) && !tr[x].del){
    			debug("upd (%d ,%d) by %d
    " ,tr[x].tp.x[0] ,tr[x].tp.x[1] ,v);
    			tr[x].val = std::min(tr[x].val ,v);
    		}
    		upd(A ,B ,lch ,v) ,upd(A ,B ,rch ,v);
    		return pushup(x);
    	}
    	void del(point A ,int x){
    		if(!x) return ;
    		if(outside(A ,A ,tr[x].mn ,tr[x].mx) || !tr[x].alive) return;
    		pushdown(x);
    		if(inside(tr[x].tp ,tr[x].tp ,A ,A)){
    			tr[x].del = true;
    			pushup(x);
    			return ;
    		}
    		del(A ,lch) ,del(A ,rch);
    		pushup(x);
    	}
    	std::pair<int ,int> getmn(){
    		return std::make_pair(tr[rt].mnval ,tr[rt].mnfr);
    	}
    	void pushall(int x){
    		if(!x) return;
    		pushdown(x);
    		pushall(lch) ,pushall(rch);
    		pushup(x);
    		outputinfo(x);
    	}
    }kdt;
    
    struct Edge{
    	int w;
    	point A ,B;
    	Edge(){w = 0 ,A = B = point();}
    	Edge(int dist ,point a ,point b){
    		w = dist;
    		A = a ,B = b;
    	}
    };
    std::vector<Edge> e[MX];
    int dis[MX];
    
    int main(){
    	__FILE([NOI2019]弹跳);
    	int n = read() ,m = read() ,w = read() ,h = read();
    	for(int i = 1 ,x ,y ; i <= n ; ++i){
    		x = read() ,y = read();
    		P[i] = point(x ,y ,(INT_MAX) >> 1 ,i);
    	}
    	kdt.buildtree(1 ,n);
    	for(int i = 1 ,p ,t ,L1 ,R1 ,L2 ,R2 ; i <= m ; ++i){
    		p = read() ,t = read();
    		L1 = read() ,L2 = read() ,R1 = read() ,R2 = read();
    		e[p].push_back(Edge(t ,point(L1 ,R1) ,point(L2 ,R2)));
    	}
    	memset(dis ,0x3f ,sizeof dis);
    	kdt.upd(P[tkdt[1]] ,P[tkdt[1]] ,kdt.rt ,0);
    	for(int i = 1 ; i <= n ; ++i){
    		// kdt.pushall(kdt.rt);
    		std::pair<int ,int> cur = kdt.getmn();
    		int x = trans[cur.second] ,dist = cur.first;
    		debug("%d updated
    " ,x);
    		kdt.del(P[cur.second] ,kdt.rt);
    		dis[x] = dist;
    		for(auto j : e[x]){
    			debug("$ TRY to update from %d...
    " ,x);
    			kdt.upd(j.A ,j.B ,kdt.rt ,dist + j.w);
    		}
    	}
    	for(int i = 2 ; i <= n ; ++i){
    		printf("%d
    " ,dis[i]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    《代码整洁之道》读书笔记六
    第九周总结
    《构建之法》读后感(五)
    学习进度条-第十二周
    3. 统计数字
    《构建之法》读后感(四)
    学习进度条-第十一周
    4. 丑数 II
    《构建之法》读后感(三)
    学习进度条-第十周
  • 原文地址:https://www.cnblogs.com/imakf/p/13721527.html
Copyright © 2020-2023  润新知