zoukankan      html  css  js  c++  java
  • sweep line 扫描线模型

    扫描线作用 & 算法步骤

    扫描线可以讲区间分成不相交的区间,对于每个区间端点,可以利用+fee -fee操作(类似于差分、前缀和思想)来求解一些最优问题。
    举栗子:一家餐厅一天会来很多客人,每个客人有一个arriveTime,leaveTime,我们想求出一天中,究竟同时又最多人的时候。

    如上区间,可以看到最多人是时候是3个人,先按照arriveTime排个序,然后每次at时都要加一,每次lt时都要减一,最后一用一个变量求最值就行。

    下面来一道题目:

    题目链接:https://atcoder.jp/contests/abc188/tasks/abc188_d
    思路:利用扫描线模型来考虑这个问题;首先不是有区间吗,譬如 1 ~ 2,是有两天的那么这个客人应该是第1天到,第3天离开,共两天(这里其实很难理解,有点类似物理,你12两天,不是有12 , 2~3 两个时间段吗?)。
    那好了,区间已经定义好了,我们在L += c ,R -= c,就能够利用上面的模型了。
    步骤如下:
    1.先把所有区间的所有端点(左端点直接放,右端点+1再放),放到set中(去重)。然后每个端点都要对应的+c 或者-c操作(L 要+ ,R要减)。
    2.为了做到上面的端点+-c,我们要做一个对应端点的映射,所以就要用到map做一个映射
    3.把set中的端点拿出来,按时间线排序,然后对于每个端点用map找到+-c的操作,结果记录在acc中;用一个res += min(acc,C) * 区间长度(set,和排序其实是相当于够着了一个无重叠的区间,这个区间就要某一/几个服务的时间,acc记录了这个段总共要多少费用)。最后res就是结果

    参考代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    #define int long long
    const int N = 2 * 1e5 + 10;
    
    set<int> s;
    int a[N] ,b[N] , c[N];
    map<int,int> ch;
    int n,C;
    
    signed main(){
    	ios::sync_with_stdio(false);
    	#ifndef  ONLINE_JUDGE
    		freopen("tpl.txt","r",stdin);
    	#endif
    	cin >> n >> C;
    	for(int i = 1; i <= n; ++i){
    		cin >> a[i] >> b[i] >> c[i];
    		s.insert(a[i]);
    		s.insert(b[i] + 1);
    		
    		ch[a[i]] += c[i];
    		ch[b[i] + 1] -= c[i];
    	}
    	
    	
    	vector<int> vc(s.begin(),s.end());
    //	sort(vc.begin(),vc.end());
    	int acc = 0;
    	int res = 0;
    	for(int i = 0; i < vc.size() - 1; i++){
    		acc += ch[vc[i]];
    		res += min(acc,C) * (vc[i+1] - vc[i]);
    	}
    	cout << res << endl;
    	
    	
    	
    }
    
  • 相关阅读:
    常忘知识点一:嵌套属性
    button按钮的状态为disabled禁用状态,click事件无法触发,但是为什么touchstart下却依然可以触发
    shell
    sql help cs
    再次写给我们这些浮躁的程序员
    C# winform进度条 (异步)
    关于C# WinForm中进度条的实现方法
    Oracle 多行记录合并/连接/聚合字符串的几种方法
    PL/SQL编码规范的一些建议
    PL/SQL 日期时间类型函数及运算
  • 原文地址:https://www.cnblogs.com/custoyth/p/sweepline.html
Copyright © 2011-2022 走看看