洛谷P2070 离散化区间
『题目传送门』:P2070 刷墙
『思路1 题解原链接』
题目:
Farmer John已经设计了一种方法来装饰谷仓旁边的长栅栏(把栅栏认为是一根一维的线)。他把一只画刷绑在他最喜爱的奶牛Bessie身上,之后就去喝一杯冰水,而Bessie隔着栅栏来回走,当她走过某个地方,这里的一段栅栏就被刷上了涂料。
Bessie从栅栏上的位置0开始,并且遵循着一个N次移动的次序(1 <= N <= 100,000)。例如“10 L”表示Bessie向左移动了10个单位长度,“15 R”表示Bessie向右移动了15个单位长度。现给出Bessie所有移动的列表,Farmer John想要知道哪些区域的栅栏至少涂了两层涂料(只涂一层涂料的区域可能在大雨中被洗掉)。Bessie在她的行走中最远到达距起始点1,000,000,000个单位长度。
题目大意:给定(n)个区间([l,r])其中区间的长度(1leq l,rleq 1e^9),要求给出区间相交数大于2的区间长度。
例如模拟给定的样例:
6 2 R 6 L 1 R 8 L 1 R 2 R
思路1 思维题:分情况考虑离散化(对区间考虑)
说实话这个有点难弄清,需要细细的思考。
思路:从小到达扫描区间,维护一个可能发生重叠的区间【L,R】,在当前维护的区间的右边寻找一个区间【a[i].l,a[i].r】
使得当前的可能区间更新:
分为两种情况:(对应到图右上角的1和2)
- 查询的区间的右端点是小于当前维护区间的右端点的,那么把【当前维护区间的左端点,当前查询区间的右端点】这一区间加入到重复区间长度计算中。并且试图在【当前查询区间的右端点,当前维护区间的右端点】寻找下一个可能的重复区间。
- 查询的区间的右端点是大于当前维护区间的右端点的,那么把【当前维护区间的左端点,当前维护区间的右端点】这一区间加入到重复区间长度计算中。并且试图在【当前维护区间的右端点,当前查询区间的右端点】寻找下一个可能的重复区间
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int n;
string dir;
ll l, r;
vector<pair<ll, ll>> alls;
ll res;
int main() {
cin >> n;
for (int i = 0; i < n; i++) {
cin >> r >> dir;
if (dir == "R")
r = l + r;
else
r = l - r;
ll tl, tr;
tl = min(l, r), tr = max(l, r);
alls.push_back(make_pair(tl, tr));
l = r;
}
sort(alls.begin(), alls.end());
//找它区间后面左端点小于右端点并且右端点最右边的点
ll lft = alls[0].first;
ll rgt = alls[0].second;
for (int i = 1; i < n; i++) {
if (alls[i].second > lft) { //至少是有意义的区间(可能的区间至少是大于1的)
//缩小左边的区间
alls[i].first = max(alls[i].first, lft);
//【alls[i].first,alls[i].second】
//【lft ,rgt 】
if (alls[i].second > rgt) { //比之前的右端点大全部覆盖
res += rgt - alls[i].first; //求公共区间
lft = rgt; //接下来有可能的区间是[rgt,alls[i].second]
rgt = alls[i].second;
} else { //比之前的右端点小
res += alls[i].second - alls[i].first; //求公共区间
lft = alls[i].second; //接下来可能的区间是[alls.second,rgt]
}
}
}
cout << res << endl;
return 0;
}
思路2:离散化+差分(对点考虑)
对于一个区间【L,R】每出现一次,就相当于在a[l]+=1,a[r+1]-=1;
那么就显而易见的,直接对区间的左右端点左修改,(m)次查询即完成了相应的修改,最后从小到大扫描所有的区间,若进入区间左端点后当前的差分值从1变为了2即开始进入到多个区间重合的区域,从2变到1即退出重合的区域。如下图
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
static int faster_iostream = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(NULL);
return 0;
}();
int n;
string dir;
ll l, r;
vector<pii> point;
ll res;
int main() {
cin >> n;
for (int i = 0; i < n; i++) {
cin >> r >> dir;
if (dir == "R")
r = l + r;
else
r = l - r;
ll tl, tr;
tl = min(l, r), tr = max(l, r);
point.push_back(make_pair(tl, 1));
point.push_back(make_pair(tr, -1));
l = r;
}
sort(point.begin(), point.end());
int old = 0;
int sum = 0;
for (int i = 0; i < point.size(); i++) {
old = sum;
sum += point[i].second;
if (old == 1 && sum == 2) l = point[i].first;
if (old == 2 && sum == 1) res += point[i].first - l;
}
cout << res << endl;
return 0;
}