• [JOISC 2020 Day4T3] 治疗方案


    题目链接

    首先我们看到题,发现不会,考虑上网搜题解,然后会发现这是一道dp.

    首先这是看出一道dp,先思考(n^2)暴力怎么做,显然我们每个操作必须"连起来"。这样才能确保所有人都被治愈。令 (dp[i]) 表示治疗到 (r[i]) 所需要的最小花费。

    我们可以得出 (dp[i] = min_{j = 1}^{m}dp[j] + c[i]), 对于所有 (j) 满足 (r[i] le l[j] + |T[i] - T[j]| + 1), 且 (j ot= i)。这个东西的时间复杂度是 (n^2) 的。

    我们发现拆了绝对值之后,每个 (i) 对应的能转移的 (j) 是原序列按 (T) 排序后,对应的一段区间。然后又能发现,这个dp可以想dij一样,每次取最小的更新。

    那么我们把它们丢到两棵(对应着拆绝对值)线段树上,然后跑一个很像最短路的东西就行了。

    我的写法时间复杂度是 (mlog^2m) , 被wasa855神仙的 (mlogm) 方法爆踩。 说明我太菜了/kk

    #include<bits/stdc++.h>
    
    using namespace std;
    
    typedef long long ll;
    #define N 100005
    #define pll pair<ll, ll>
    
    int n, m;
    
    struct qus
    {
    	int T, l, r;
    	ll c;
    
    	bool operator < (const qus &o) const
    	{
    		return T < o.T;
    	}
    }a[N];
    
    ll dis[N];
    
    priority_queue <pll> q;
    
    bool vis[N], inq[N];
    
    struct Seg
    {
    	set <pll> s[N << 2];
    
    	void insert(int rt, int l, int r, int x, pll v)
    	{
    		s[rt].insert(v);
    		if(l == r) return;
    		int mid = l + r >> 1;
    		if(x <= mid) insert(rt << 1, l, mid, x, v);
    		else insert(rt << 1 | 1, mid + 1, r, x, v);
    	}
    
    	void update(int rt, int l, int r, int x, int y, int v, ll p)
    	{
    		// cout << l << ' ' << r << ' ' << x << ' ' << y << endl;
    		if(l == x && r == y)
    		{
    			for(; !s[rt].empty() && s[rt].begin()->first <= v;)
    			{
    				int u = s[rt].begin()->second;
    				if(!inq[u])
    				{
    					inq[u] = 1;
    					dis[u] = p + a[u].c;
    					q.push(make_pair(-dis[u], u));
    				}
    				s[rt].erase(s[rt].begin());
    			}
    			return;
    		}
    		int mid = l + r >> 1;
    		if(y <= mid) update(rt << 1, l, mid, x, y, v, p);
    		else if(x > mid) update(rt << 1 | 1, mid + 1, r, x, y, v, p);
    		else update(rt << 1, l, mid, x, mid, v, p), update(rt << 1 | 1, mid + 1, r, mid + 1, y, v, p);
    	}
    }tr1, tr2;
    
    int main()
    {
    	scanf("%d%d", &n, &m);
    	for(int i = 1; i <= m; i++)
    	{
    		scanf("%d%d%d%d", &a[i].T, &a[i].l, &a[i].r, &a[i].c);
    	}
    	sort(a + 1, a + m + 1);
    	for(int i = 1; i <= m; i++) tr1.insert(1, 1, m, i, make_pair(a[i].l - a[i].T, i));
    	for(int i = 1; i <= m; i++) tr2.insert(1, 1, m, i, make_pair(a[i].l + a[i].T, i));
    	for(int i = 1; i <= m; i++) dis[i] = (a[i].l == 1) ? a[i].c : (1ll << 60);
    	for(int i = 1; i <= m; i++) if(a[i].l == 1) inq[i] = 1, q.push(make_pair(-a[i].c, i));
    	while(!q.empty())
    	{
    		int u = q.top().second; q.pop();
    		// cout << u << endl;
    		if(vis[u]) continue;
    		vis[u] = 1;
    		if(u != 1) tr1.update(1, 1, m, 1, u - 1, a[u].r - a[u].T + 1, dis[u]);
    		if(u != m) tr2.update(1, 1, m, u + 1, m, a[u].r + a[u].T + 1, dis[u]);
    	}
    	ll ans = (1ll << 60);
    	for(int i = 1; i <= m; i++) 
    	{
    		if(a[i].r == n)
    		{
    			ans = min(ans, dis[i]);
    		}
    	}
    	if(ans != (1ll << 60)) printf("%lld
    ", ans);
    	else printf("-1
    ");
    	return 0;
    }
    
  • 相关阅读:
    统计创建对象个数
    动手动脑
    开学第一周心得
    放假第五周总结
    放假第四周总结
    第一周总结
    04-异常处理-动手动脑
    03-继承与多态-动手动脑
    02-类和对象-跟踪类对象创建个数
    02-类和对象-动手动脑
  • 原文地址:https://www.cnblogs.com/LJB00131/p/12582379.html
Copyright © 2020-2023  润新知