Solution
有一些个位置一定是不能存在忍者的。于是我们把这些位置拿走,给所有的数据重标号。
做法:开一个长度为
n
n
的数组,对于一定是 的一段我们全赋为
1
1
。最终我们把为 的扔掉即可。可以用差分
/
/
线段树维护。
若重标号后, ,那么所有草丛都必须有忍者。特判掉。
而若一个区间
A
A
完全包含另一个 (
A
A
是大的 ),那么我们只保留 即可。
做法:把所有区间按
l
l
从大到小排序,然后我们对于 ,记录
mini−1j=1r[i]
min
j
=
1
i
−
1
r
[
i
]
,若这个值小于
r[i]
r
[
i
]
,那区间
i
i
必定完全包含某个区间,删掉。
原因:在 前面的区间
j
j
,均有 ,而存在
r[j]≤r[i]
r
[
j
]
≤
r
[
i
]
,则它一定要被删。
我们单独考虑,如果要放最少的忍者而满足所有条件怎么做?
把所有区间按右端点排序。枚举每个区间,若这个区间内已经有忍者,那么continue;否则在右端点处放置一个忍者。(对后面贡献一定最大)
考虑什么时候一个点必须放忍者。即,我们在这个区间的 r−1 r − 1 的位置放一个,使得总忍者数依然不超过 k k 。
于是定义 :满足
[1,i]
[
1
,
i
]
至少放置的忍者数。(正推,贪心的放在右端点)
同样地有
g[i]
g
[
i
]
:满足
[i,n]
[
i
,
n
]
至少放置的忍者数。(逆推,贪心的放在左端点)
对于一个区间的
r−1
r
−
1
,我们找出它能满足的一段区间,设为
[ql,qr]
[
q
l
,
q
r
]
。
由于在我们去掉包含关系后,所有的区间均满足左右端点同时严格单调递增。
所以我们可以二分出
ql
q
l
与
qr
q
r
。
那么需要的忍者数为:
f[ql−1]+f[qr+1]+1
f
[
q
l
−
1
]
+
f
[
q
r
+
1
]
+
1
。
若这个数大于
k
k
,那么 一定必须,否则一定不必须。
Code
#include <bits/stdc++.h>
using namespace std;
#define N 100010
struct item {int x, y, c;}a[N], d[N];
bool cmp1(item A, item B) {return A.c > B.c;}
bool cmp2(item A, item B) {return A.x == B.x ? A.y < B.y : A.x > B.x;}
bool cmp3(item A, item B) {return A.y < B.y;}
int n, k, m, b[N], mn[N], mx[N], f[N], g[N], isr[N], rl[N];
multiset<int> S;
int main() {
scanf("%d%d%d", &n, &k, &m);
memset(b, 0, sizeof(b));
for(int i = 1; i <= m; ++i) {
scanf("%d%d%d", &a[i].x, &a[i].y, &a[i].c);
if(!a[i].c) ++b[a[i].x], --b[a[i].y + 1];
}
for(int i = 1; i <= n; ++i) b[i]+= b[i - 1];
int pre = 0;
for(int i = 1; i <= n; ++i) {
if(!b[i]) ++pre, rl[pre] = i;
mn[i] = pre;
}
++pre;
for(int i = n; i >= 1; --i) {
if(!b[i]) --pre;
mx[i] = pre;
}
n = mn[n];
for(int i = 1; i <= m; ++i) {
if(!a[i].c) continue;
a[i].x = mx[a[i].x];
a[i].y = mn[a[i].y];
if(a[i].x > a[i].y || a[i].x > n || a[i].x <= 0 || a[i].y <= 0 || a[i].y > n) a[i].c = 0;
}
if(n == k) {
for(int i = 1; i <= n; ++i) printf("%d\n", rl[i]);
return 0;
}
sort(a+1, a+m+1, cmp1);
for(int i = 1; i <= m; ++i) if(!a[i].c) {m = i - 1; break;}
memcpy(d, a, sizeof(d));
sort(d+1, d+m+1, cmp2);
for(int i = 1; i <= m; ++i) {
if(S.begin() != S.end() && (*S.begin()) <= d[i].y) d[i].c = 0;
else S.insert(d[i].y), d[i].c = 1;
}
memcpy(a, d, sizeof(a));
sort(a+1, a+m+1, cmp1);
for(int i = 1; i <= m; ++i) if(!a[i].c) {m = i - 1; break;}
sort(a+1, a+m+1, cmp3);
pre = 0; f[0] = 0;
for(int i = 1; i <= m; ++i) {
f[i] = f[i - 1]; isr[i] = 0;
if(!(a[i].x <= pre && pre <= a[i].y)) ++f[i], pre = a[i].y, isr[i] = 1;
}
pre = n + 1; g[m + 1] = 0;
for(int i = m; i >= 1; --i) {
g[i] = g[i + 1];
if(!(a[i].x <= pre && pre <= a[i].y)) ++g[i], pre = a[i].x;
}
bool prt = 0;
for(int i = 1; i <= m; ++i) {
if(!isr[i]) continue;
if(a[i].x == a[i].y) {printf("%d\n", rl[a[i].y]); prt = 1; continue;}
int l = 1, r = i - 1, ql = 0, qr = m + 1;
while(l <= r) {
int mid = (l + r)>>1;
if(a[mid].y < a[i].y - 1) ql = mid, l = mid + 1;
else r = mid - 1;
}
l = i + 1, r = m;
while(l <= r) {
int mid = (l + r)>>1;
if(a[i].y - 1 < a[mid].x) qr = mid, r = mid - 1;
else l = mid + 1;
}
if(f[ql] + g[qr] + 1 > k) printf("%d\n", rl[a[i].y]), prt = 1;
}
if(!prt) puts("-1");
return 0;
}