二维无序LIS ACdream1216 Beautiful People

传送门:点击打开链接

题意:告诉你n个人,每个人有个s和b连个值,要求从n个人中选出数量最多的人,使任意两个人(i,j)都有si<sj且bi<bj或者sj<si且bj<bi,要求输出选出数量最多的人,且输出是哪一些人,其中题目是spj。

思路:首先很容易想到DAG模型,但是这题的n<=100000,所以用DAG模型复杂度太高了。然后会想到LIS,可能就会想到用二维线段树去做。

其实仔细想想这道题,和普通的LIS还是有不一样的地方的。那就是他的顺序并不是给定的!!什么意思呢,虽说是二维LIS,但是他给出的n个人,并不是必须要递增,而是只要选出一部分,然后排序一下,让他们递增就可以了,其实这就是在提示你,可以稍微处理一下输入,比如排序什么的,这是普通的LIS不能做的。这里排序也非常的巧妙

按照s从小到大排序,s相同时按照b从大到小排序,那么这样排序有什么好处呢。我们可以看下排序以后的样例

1 2,1 1,2 2,2 1

可以发现,s总是增大的(废话),那么如果我们按照b去做LIS会怎样呢?

首先,1 2和1 1绝对不会出现在同一个LIS中,因为b是从大到小排序的,如果是s相同的时候,b在LIS中最多只会被取一次,因为本身b是递减的,但是在LIS中是递增的,所以只会存在一个。所以排序后对b做LIS就是答案了,然而另外一个问题在于如何打印答案。

有两种方法用O(nlogn)的复杂度去处理LIS,一种是线段树,可以做到打印路径且字典序最小,一种是二分查找,但是不好处理字典最小,好在题目是spj,所以我们同样可以采用二分的方法。

直接标记某个位置结尾的LIS的大小,然后从后往前扫,从最大的LIS往1去找对应的输出,一定不能从前向后扫,因为答案会不对,只有从后向前扫,此时才是一个完整的LIS路径

#include<map>
#include<set>
#include<cmath>
#include<stack>
#include<queue>
#include<cstdio>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w+",stdout)
using namespace std;
typedef long long LL;
typedef pair<int, int>PII;

const int MX = 1e5 + 5;
const int INF = 0x3f3f3f3f;

struct Node {
    int x, y, id;
    bool operator<(const Node &b)const {
        if(x == b.x) return y > b.y;
        return x < b.x;
    }
} A[MX];

int d[MX], mark[MX];

int main() {
    int n; //FIN;
    while(~scanf("%d", &n)) {
        memset(d, INF, sizeof(d));
        memset(mark, 0, sizeof(mark));

        for(int i = 1; i <= n; i++) {
            A[i].id = i;
            scanf("%d%d", &A[i].x, &A[i].y);
        }
        sort(A + 1, A + 1 + n);

        int ans = 0;
        for(int i = 1; i <= n; i++) {
            int p = lower_bound(d + 1, d + 1 + n, A[i].y) - d;

            mark[i] = p;
            ans = max(ans, p);
            d[p] = A[i].y;
        }

        printf("%d\n", ans);
        for(int i = n, j = ans; i >= 1; i--) {
            if(mark[i] == j) {
                printf("%d%c", A[i].id, j == 1 ? '\n' : ' ');
                j--;
            }

        }
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-15 22:15:55

二维无序LIS ACdream1216 Beautiful People的相关文章

HDU 1069 Monkey and Banana(二维偏序LIS的应用)

---恢复内容开始--- Monkey and Banana Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 13003    Accepted Submission(s): 6843 Problem Description A group of researchers are designing an experiment to te

acd - 1216 - Beautiful People(二维LIS)

题意:一个人有两个属性S, B(1 ≤ Si, Bi ≤ 10^9),当两个人的这两个属性满足 S1 < S2 && B1 < B2 或者 S1 > S2 && B1 > B2 时,这两个人不会讨厌对方.现给出 N 个人(2 ≤ N ≤ 100 000)的属性,求最多能有多少个人,他们之间任意两人都不会讨厌对方. 题目链接:http://acdream.info/problem?pid=1216 -->>容易想到是一个二维的LIS模型..

HDU 1025 Constructing Roads In JGShining&#39;s Kingdom(二维LIS)

Constructing Roads In JGShining's Kingdom Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 23467    Accepted Submission(s): 6710 Problem Description JGShining's kingdom consists of 2n(n is no mo

hdu----(1677)Nested Dolls(DP/LIS(二维))

Nested Dolls Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2704    Accepted Submission(s): 802 Problem Description Dilworth is the world’s most prominent collector of Russian nested dolls: he

二维LIS(CDQ分治)

题目描述 给定一个长度为N的序列S,S的每个元素pi是一个二元组(xi,yi),定义pi<pj当且仅当xi<xj并且yi<yj,求S的最长上升子序列长度 输入格式 第一行一个N,表示一共有N个元素 接下来有N行,每行包含两个正整数xi,yi 输出格式 输出一行一个整数,代表序列S的最长上升子序列的长度 一道很好的模板题 1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 usin

UVA10285 二维 LIS

题意: 求二维数组最长不下降子序列 解题: 记忆化搜索, d[i][j]为以 (i, j) 为终点的最长不下降序列的长度,然后四个方向 dfs ~ #include <bits/stdc++.h> #define ll long long using namespace std; const int maxn = 110; const int INF = 0x3f3f3f3f; char nm[maxn]; int a[maxn][maxn], d[maxn][maxn]; int gx[4]

SGU 199 Beautiful People 二维最长递增子序列

题目链接: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=20885 题意: 求二维最长严格递增子序列. 题解: O(n^2)的算法很好想,不过这里会t掉,只能O(nlogn) 于是用二分来维护: 先把所有的数按x递增排序,x相同的按y递减排序(这里之所以要按y递减排序是因为为了写代码方便,递减的话你后面基本就只要考虑y的大小,如果不递减,你还要考虑x的大小的,具体的可以自己思考一下) 排完序之后我们接下来就只考虑y的大小

【二维树状数组】See you~

https://www.bnuoj.com/v3/contest_show.php?cid=9148#problem/F [题意] 给定一个矩阵,每个格子的初始值为1.现在可以对矩阵有四种操作: A x y n1 :给格点(x,y)的值加n1 D x y n1: 给格点(x,y)的值减n1,如果现在格点的值不够n1,把格点置0 M x1 y1 x2 y2:(x1,y1)移动给(x2,y2)n1个 S x1 y1 x2 y2 查询子矩阵的和 [思路] 当然是二维树状数组 但是一定要注意:lowbi

[CF 848B] Rooter&#39;s Song 二维弹性碰撞

题意 在平面直角坐标系中, 有一个以 (0, 0) 为左下角, (w, h) 为右上角的矩形. 有 n 个人, 它们一开始站在 x 轴或者 y 轴上, 第 i 个人的坐标为 $p_i$ , 准备跳舞. 对于第 i 个人, 它最开始会在原地站立 t 秒, 然后朝着矩形的对面跳舞, 每 1s 跳 1 个单位长度. 如果两个人相遇了, 那么它们会相互走另一个人的路线. 人们会一直走着, 直到它们到达了矩形的某个边界. 问每个人最后会走到的坐标. 分析 二维弹性碰撞. 大致地思路是先回顾一维弹性碰撞,