zoukankan      html  css  js  c++  java
  • 「JOISC 2020 Day4」治疗计划

    题目

    传送门

    解法

    真的毫无头绪... 一直在想如何按时间顺序 (mathtt{dp}),然后就死了...

    不妨换一个角度,令 (dp_i) 为使 ([1,i]) 的居民健康的最小代价。转移有:

    [dp_i=min dp_j+c_i (r_j-l_i+1ge |t_i-t_j|) ]

    注意 (dp_i) 并不考虑 (i) 后的病毒传染过来的情况,因为这种情况会被后面的 (dp) 值所考虑。

    解释一下这个条件:

         r_j
    ------- 段 j
        ------------ 段 i
       l_i
    
    1. (t_i>t_j)。在执行 (j) 方案后到执行 (i) 方案前的时间里,会从 (r_j) 开始被感染。
    2. (t_ile t_j)。在执行 (i) 方案后到执行 (j) 方案前的时间里,会从 (l_i) 开始被感染。因为如果我们需要方案 (j),显然 (l_i) 以左是感染区。

    如何优化?本来想用 (mathtt{cdq}) 分治,但仔细想想有个巨大的 ( ext{bug}):用 (mathtt{cdq}) 分治肯定是将 (t) 排序从而去掉绝对值,但 (mathtt{dp}) 根本就不应该按 (t) 来转移啊!

    这里有个很 ( m nb) 的转移方式 —— 类 Dijkstra

    用优先队列存下 (mathtt{dp}) 值来进行转移,那么我们可以直接给转移到的方案进行赋值,这就相当于取 (min) 操作!同时,由于每个方案只被更新一次,我们可以保证线段树中 modify() 函数的时间复杂度。

    总时间复杂度大概(mathcal O(nlog n))

    代码

    #include <queue>
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    #define print(x,y) write(x),putchar(y) 
    
    template <class T> inline T read(const T sample) {
        T x=0; int f=1; char s;
        while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
        while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
        return x*f;
    }
    template <class T> inline void write(const T x) {
        if(x<0) return (void) (putchar('-'),write(-x));
        if(x>9) write(x/10);
        putchar(x%10^48);
    }
    
    typedef long long ll;
    typedef pair <ll,int> pii;
    
    const int maxn=1e5+5;
    const ll inf=1e16;
    
    int n,m;
    ll f[maxn];
    struct Plan {
    	int t,l,r,c;
    	
    	bool operator < (const Plan a) const {
    		return t<a.t;
    	}
    } p[maxn];
    struct Tree {
    	ll mn[2];
    } t[maxn<<2];
    priority_queue <pii> q;
    
    void pushUp(int o) {
    	if(!o) return;
    	t[o].mn[0]=min(t[o<<1].mn[0],t[o<<1|1].mn[0]);
    	t[o].mn[1]=min(t[o<<1].mn[1],t[o<<1|1].mn[1]);
    }
    
    void init(int o,int l,int r,int pos,ll x,ll y) {
    	if(l>pos or r<pos) return;
    	if(l==r) {
    		t[o].mn[0]=x-y,t[o].mn[1]=x+y;
    		return;
    	}
    	int mid=l+r>>1;
    	init(o<<1,l,mid,pos,x,y);
    	init(o<<1|1,mid+1,r,pos,x,y);
    	pushUp(o);
    } 
    
    void modify(int o,int l,int r,int L,int R,ll lim,ll dp,bool d) {
    	if(l>R or r<L or t[o].mn[d]>lim)
    		return;
    	if(l==r) {
    		f[l]=dp+p[l].c,q.push(make_pair(-f[l],l));
    		t[o].mn[0]=t[o].mn[1]=inf;
    		return;
    	}
    	int mid=l+r>>1;
    	modify(o<<1,l,mid,L,R,lim,dp,d);
    	modify(o<<1|1,mid+1,r,L,R,lim,dp,d);
    	pushUp(o);
    }
    
    signed main() {
    	m=read(9),n=read(9);
    	for(int i=1;i<=n;++i)
    		p[i].t=read(9),p[i].l=read(9),
    		p[i].r=read(9),p[i].c=read(9),
    		f[i]=inf;
    	sort(p+1,p+n+1);
    	for(int i=1;i<=n;++i)
    		if(p[i].l==1) {
    			f[i]=p[i].c;
    			q.push(make_pair(-f[i],i));
    			init(1,1,n,i,inf,0);
    		}
    		else init(1,1,n,i,p[i].l,p[i].t);
    	while(!q.empty()) {
    		pii u=q.top(); q.pop();
    		int x=u.second;
    		modify(1,1,n,1,x-1,p[x].r-p[x].t+1,f[x],0);
    		modify(1,1,n,x+1,n,p[x].r+p[x].t+1,f[x],1);
    	}
    	ll ans=inf;
    	for(int i=1;i<=n;++i)
    		if(p[i].r==m)
    			ans=min(ans,f[i]);
    	print(ans==inf?-1:ans,'
    ');
    	return 0;
    }
    
  • 相关阅读:
    完美世界经典版本881外挂
    ShowModal 动态创建窗体和释放窗体
    HTML 颜色代码大全
    padding margin border 的四值顺序
    三 C# Socket通信 窗体控件与多线程
    Java解压缩Zip 文件
    八 C# Socket通信 通信协议设计
    CSS+DIV实现鼠标经过背景变色
    七 C# Socket通信 阻塞性线程的快速终止
    二 C# Socket通信模式
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/15019502.html
Copyright © 2011-2022 走看看