题意:
两个区间:[Si, Ei] 和 [Sj, Ej] (0 <= S < E <= 10^5)
若 Si <= Sj,且 Ej <= Ei 且 Ei - Si > Ej - Sj, 则第i个区间覆盖第j个区间,即牛i比牛j强壮。问对于每一头牛i有多少头牛比它强壮。
解析:
这题先一看,不知如何下手。首先,将每个区间的S和E当做是(S,E)一个点,这样子把所有点在坐标系上画出来,你就会发现一个很神奇的现象,题目要求就会变成:问每一个点的左上角有多少个点?
那么这题转化为了,每个点的左上角有多少个点。但是点不是有序排好的,要预处理一下就可以。
如果正常做,那个y是递增的,所以sum和update那个方向就会相反了,这个其实没什么所谓,一样的,排序的时候先y由大到小排,y相同时x由小到大排,这样小小的处理,就变成stars那题了!首先将E[i]降序排序如果相等,则按S[i]的升序排序。那么执行完这部操作之后前面的
E[i]肯定 >= 后面的E[i],现在只要考虑S[i]就好了,每次计算S[i]之前有多少个点。
统计完之后将S[i]的位置加1,并更新线段树。
注意:
这题需要离散化,如果两头牛的区间相同,则当前牛比它大的个数等于前面牛比它大的个数。
AC代码
#include <cstring>
#include <cstdio>
#include <algorithm>
#define ls o*2
#define rs o*2+1
using namespace std;
const int N = 1e5 + 10;
struct Cow {
int s, e, id;
}cow[N];
int sumv[N << 2], ans[N];
bool cmp(Cow a, Cow b) {
if(a.e != b.e)
return a.e > b.e;
return a.s < b.s;
}
int ql, qr;
int query(int o, int L, int R) {
if(ql <= L && R <= qr) return sumv[o];
int M = (L + R)/2, ret = 0;
if(ql <= M) ret += query(ls, L, M);
if(M < qr) ret += query(rs, M+1, R);
return ret;
}
int p, v;
void modify(int o, int L, int R) {
if(L == R) {
sumv[o] += v;
return ;
}
int M = (L + R)/2;
if(p <= M) modify(ls, L, M);
else modify(rs, M+1, R);
sumv[o] = sumv[ls] + sumv[rs];
}
int main() {
int n;
while(~scanf("%d", &n) && n) {
for(int i = 1; i <= n; i++) {
scanf("%d%d", &cow[i].s, &cow[i].e);
cow[i].s++, cow[i].e++;
cow[i].id = i;
}
sort(cow+1, cow+1+n, cmp);
memset(sumv, 0, sizeof(sumv));
for(int i = 1; i <= n; i++) {
if(i > 1 && cow[i].s == cow[i-1].s && cow[i].e == cow[i-1].e) {
ans[cow[i].id] = ans[cow[i-1].id];
}else {
ql = 0, qr = cow[i].s;
ans[cow[i].id] = query(1, 1, n);
}
p = cow[i].s, v = 1;
modify(1, 1, n);
}
printf("%d", ans[1]);
for(int i = 2; i <= n; i++) {
printf(" %d", ans[i]);
}puts("");
}
return 0;
}