这个题目我AC之后看了一下别人的题解,基本上都是线段树,不过二分也可以。
这个题目很自然就肯定要对其中一个进行排序,排完序之后再处理另外一边,另一边记得离散化。
怎么处理呢,你仔细想想,找找规律就可以发现,其实我们就是在找递增子序列。
第一次找到的就是重要程度为1 的妹子,然后删除这些元素,继续第二次找,第二次找到的就是重要程度为二的妹子。
所以到每一个点,我们就只要根据它的大小来判断它应该放的位置(尽量靠前,并且小于这个数),然后更新这个位置,再返回这个位置,它所在的位置就是它的重要程度。
emmm 其实就是用一个数组,数组的每一个位置 i 存的就是到目前位置重要程度为 i 的最大值。
具体看代码吧。
#include <cstdio> #include <cstdlib> #include <cstring> #include <queue> #include <vector> #include <algorithm> #include <string> #include <iostream> #include <map> #define inf 0x3f3f3f3f #define inf64 0x3f3f3f3f3f3f3f3f using namespace std; const int maxn = 2e5 + 10; typedef long long ll; int num[maxn]; map<ll, ll>mp; struct node { int l, r; int sum; }tree[4*maxn]; struct edge { ll a, b, id, num, ans; }ex[maxn]; bool cmp(edge a,edge b) { return a.a > b.a; } bool cmp1(edge a,edge b) { return a.b < b.b; } bool cmp2(edge a,edge b) { return a.id < b.id; } int tot = 0; int ok(ll x) { if (x > num[1]) return 1; if (x < num[tot]) { tot++; return tot; } int l = 1, r = tot, ans = 0; int mid = (l + r) >> 1; while (l <= r) { int mid = (l + r) / 2; if (num[mid]<x) ans = mid, r = mid - 1; else l = mid + 1; } return ans; } int main() { int n; scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%lld%lld", &ex[i].a, &ex[i].b), ex[i].id = i; } sort(ex + 1, ex + 1 + n, cmp1); for (int i = 1; i <= n; i++) mp[ex[i].b] = i; sort(ex + 1, ex + 1 + n, cmp); num[1] = mp[ex[1].b]; ex[1].ans = 1; tot = 1; for(int i=2;i<=n;i++) { int f = ok(mp[ex[i].b]); // printf("%lld ex[%d]=%lld f=%d ",mp[ex[i].b], i, ex[i].b, f); num[f] = mp[ex[i].b]; ex[i].ans = f; } sort(ex + 1, ex + 1 + n, cmp2); for (int i = 1; i <= n; i++) printf("%lld ", ex[i].ans); return 0; }
网上的线段树的方法我感觉和逆序对有点像,就是首先还是把 b 离散化,然后对 a 进行排序,
然后从 1 ~ n 遍历,如果对于每一个 b 首先判断 b ~ n 有没有值,其实就是有没有比 b 大的再前面放过了,有的话就去最大值,重要程度就是 最大值+1 (这个是因为存进去的就是最大值)
没有那么重要程度就是 1 ,然后再更新这个点 b 把 b 的重要程度放到线段树的 b 这个位置以便后面的查询。
这个很好写的。
#include <cstdio> #include <cstdlib> #include <cstring> #include <queue> #include <vector> #include <algorithm> #include <string> #include <iostream> #include <map> #define inf 0x3f3f3f3f #define inf64 0x3f3f3f3f3f3f3f3f using namespace std; const int maxn = 2e5 + 10; typedef long long ll; map<ll, ll>mp; struct node { int l, r; int num; }tree[4*maxn]; struct edge { ll a, b, id, num, ans; }ex[maxn]; bool cmp(edge a,edge b) { return a.a > b.a; } bool cmp1(edge a,edge b) { return a.b < b.b; } bool cmp2(edge a,edge b) { return a.id < b.id; } void build(int id, int l, int r) { tree[id].l = l; tree[id].r = r; if (l == r) { tree[id].num = 0; return; } int mid = (l + r) >> 1; build(id << 1, l, mid); build(id << 1 | 1, mid + 1, r); } int query(int id, int x, int y) { int l = tree[id].l; int r = tree[id].r; if (x <= l && y >= r) { // printf("id=%d sum=%d ", id,tree[id].sum); return tree[id].num; } int ans = 0; int mid = (l + r) >> 1; if (x <= mid) ans = max(ans, query(id << 1, x, y)); if (y > mid) ans = max(ans, query(id << 1 | 1, x, y)); // printf("id=%d ans=%d l=%d r=%d x=%d y=%d ", id, ans, l, r,x,y); return ans; } void push_up(int id) { tree[id].num = max(tree[id << 1].num , tree[id << 1 | 1].num); } void update(int id, int x,int val) { int l = tree[id].l; int r = tree[id].r; if (l == r) { tree[id].num = val; return; } int mid = (l + r) >> 1; if (x <= mid) update(id << 1, x,val); else update(id << 1 | 1, x,val); push_up(id); } int main() { int n; scanf("%d", &n); for (int i = 1; i <= n; i++) { scanf("%lld%lld", &ex[i].a, &ex[i].b), ex[i].id = i; } sort(ex + 1, ex + 1 + n, cmp1); for (int i = 1; i <= n; i++) mp[ex[i].b] = i; sort(ex + 1, ex + 1 + n, cmp); build(1, 1, n); for(int i=1;i<=n;i++) { int f = query(1, mp[ex[i].b], n) + 1; ex[i].ans = f; update(1, mp[ex[i].b],f); } sort(ex + 1, ex + 1 + n, cmp2); for (int i = 1; i <= n; i++) printf("%lld ", ex[i].ans); return 0; }