zoukankan      html  css  js  c++  java
  • POJ2374 Fence Obstacle Course 【线段树】

    题目链接

    POJ2374

    题解

    题意:
    给出(n)个平行于(x)轴的栅栏,求从一侧栅栏的某个位置出发,绕过所有栅栏到达另一侧(x = 0)位置的最短水平距离

    往上说都是线段树优化dp
    我写了一个奇怪的线段树过了,似乎并没有和dp沾边

    因为每次都是从某个栅栏的端点出发,到达某个位置的值等于[所有这些可出发的端点已产生的代价 + 到达这个点的距离] 的最小值
    就用线段树维护每个区间
    (lm[u])表示在这个区间内的端点到达左端点的最小代价
    (rm[u])表示到右端点的最小代价

    然后每出现一层栅栏,计算出左右端点来更新线段树,同时清空被新栅栏覆盖的区间【因为这些端点已经无法直接到达下一层区间了】

    PS:
    一开始看错题了,栅栏的顺序是反过来的
    在察觉看错题之前,拿了往上若干AC程序对拍
    拍出一个惊人小数据,竟所有程序输出都不一样!!
    5 0
    3 4
    -4 5
    -4 0
    1 3
    2 3
    最终画图钦定,,我把它们hack掉了

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define cls(s) memset(s,0,sizeof(s))
    #define ls (u << 1)
    #define rs (u << 1 | 1)
    using namespace std;
    const int maxn = 200005,maxm = 100005,INF = 1000000000;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    const int ll = 1,rr = 200001,P = 100001;
    int lm[maxn << 2],rm[maxn << 2],tag[maxn << 2];
    void upd(int u,int l,int r){
    	int mid = l + r >> 1;
    	lm[u] = min(lm[ls],lm[rs] + (mid - l + 1));
    	rm[u] = min(rm[rs],rm[ls] + (r - mid));
    }
    void pd(int u){
    	if (tag[u]){
    		lm[ls] = rm[ls] = lm[rs] = rm[rs] = INF;
    		tag[ls] = tag[rs] = 1;
    		tag[u] = 0;
    	}
    }
    void modify(int u,int l,int r,int pos,int v){
    	if (l == r){
    		lm[u] = min(lm[u],v);
    		rm[u] = min(rm[u],v);
    		return;
    	}
    	pd(u);
    	int mid = l + r >> 1;
    	if (mid >= pos) modify(ls,l,mid,pos,v);
    	else modify(rs,mid + 1,r,pos,v);
    	upd(u,l,r);
    }
    void reset(int u,int l,int r,int L,int R){
    	if (l >= L && r <= R){lm[u] = rm[u] = INF; tag[u] = 1; return;}
    	pd(u);
    	int mid = l + r >> 1;
    	if (mid >= L) reset(ls,l,mid,L,R);
    	if (mid < R) reset(rs,mid + 1,r,L,R);
    	upd(u,l,r);
    }
    int query(int u,int l,int r,int pos){
    	if (l == r) return min(lm[u],rm[u]);
    	pd(u);
    	int mid = l + r >> 1;
    	if (mid >= pos) return min(lm[rs] + (mid - pos + 1),query(ls,l,mid,pos));
    	return min(rm[ls] + (pos - mid),query(rs,mid + 1,r,pos));
    }
    void build(int u,int l,int r){
    	if (l == r){lm[u] = rm[u] = INF; return;}
    	int mid = l + r >> 1;
    	build(ls,l,mid);
    	build(rs,mid + 1,r);
    	upd(u,l,r);
    }
    int ql[maxn],qr[maxn];
    int main(){
    	int n,s,l,r,ld,rd;
    	while (~scanf("%d%d",&n,&s)){
    		s += P;
    		build(1,ll,rr);
    		modify(1,ll,rr,s,0);
    		for (int i = 1; i <= n; i++) ql[i] = read(),qr[i] = read();
    		for (int i = n; i; i--){
    			l = ql[i] + P; r = qr[i] + P;
    			ld = query(1,ll,rr,l);
    			rd = query(1,ll,rr,r);
    			if (l + 1 <= r - 1) reset(1,ll,rr,l + 1,r - 1);
    			modify(1,ll,rr,l,ld);
    			modify(1,ll,rr,r,rd);
    		}
    		printf("%d
    ",query(1,ll,rr,P));
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    Python爬虫之记录一次下载验证码的尝试
    Python之学会测试,让开发更加高效(一)
    NLP(二十八)多标签文本分类
    NLP(二十七)开放领域的三元组抽取的一次尝试
    NLP(二十六)限定领域的三元组抽取的一次尝试
    Numpy之数据保存与读取
    TortoiseGit的首次使用
    NLP(二十五)实现ALBERT+Bi-LSTM+CRF模型
    NLP(二十四)利用ALBERT实现命名实体识别
    NLP(二十三)序列标注算法评估模块seqeval的使用
  • 原文地址:https://www.cnblogs.com/Mychael/p/9021839.html
Copyright © 2011-2022 走看看