Codeforces Round #222 (Div. 1) D. Developing Game 线段树有效区间合并

D. Developing Game

Pavel is going to make a game of his dream. However, he knows that he can‘t make it on his own so he founded a development company and hired n workers of staff. Now he wants to pick n workers from the staff who will be directly responsible for developing a game.

Each worker has a certain skill level vi. Besides, each worker doesn‘t want to work with the one whose skill is very different. In other words, the i-th worker won‘t work with those whose skill is less than li, and with those whose skill is more than ri.

Pavel understands that the game of his dream isn‘t too hard to develop, so the worker with any skill will be equally useful. That‘s why he wants to pick a team of the maximum possible size. Help him pick such team.

Input

The first line contains a single integer n (1 ≤ n ≤ 105) — the number of workers Pavel hired.

Each of the following n lines contains three space-separated integers liviri (1 ≤ li ≤ vi ≤ ri ≤ 3·105) — the minimum skill value of the workers that the i-th worker can work with, the i-th worker‘s skill and the maximum skill value of the workers that the i-th worker can work with.

Output

In the first line print a single integer m — the number of workers Pavel must pick for developing the game.

In the next line print m space-separated integers — the numbers of the workers in any order.

If there are multiple optimal solutions, print any of them.

Examples

input

42 8 91 4 73 6 85 8 10

output

31 3 4

题意:

  给你n个人的 位置v[i],同时每个人有一个可接受范围 l[i], r[i];

  现在让你选尽量多的人,使得被选的人 都能互相接受

  输出人数及选择方案

题解

  这个题看到不太会

  对于两个人来说要让它们相互接受可以有以下情况

          l1          v1              r1

                  l2  v2      r2

             l2            v2     r2 

            l2           v2              r2

           l2                     v2     r2

  发现一些规则

  就是相交范围就是l1 v1 与 l2 v2的相交的一段,但是当v2超过r1的时候,就不可行了

  所有我们可以想到一种 加上,减去的操作,

  当v1 出现我们在线段树上加入l1,v1的这段有效的区间

  当走过r1的时候 把l1 v1在线段树上减去即可

  显然对于一条线段要拆成两条线段, l1 v1 1 v1 和   l1 v1 -1 v2

  再在线段树上操作就可以了

  统计答案的时候呢,也可以利用线段树有效区间出来

  @doubility

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define ls i<<1
#define rs ls | 1
#define mid ((ll+rr)>>1)
#define pii pair<int,int>
#define MP make_pair
typedef long long LL;
const long long INF = 1e18+1LL;
const double Pi = acos(-1.0);
const int N = 5e5+10, M = 2e5+20, mod = 1e9+7, inf = 2e9;

int n;
int tag[N*4],mx[N*4];
void push_up(int i) {
        mx[i] = max(mx[ls],mx[rs]);
}
void push_down(int i,int ll,int rr) {
    if(tag[i] != 0 && ll != rr) {
        tag[ls] += tag[i];
        tag[rs] += tag[i];
        mx[ls] += tag[i];
        mx[rs] += tag[i];
        tag[i] = 0;
    }
}
void update(int i,int ll,int rr,int l,int r,int v)
{
    push_down(i,ll,rr);
    if(l == ll && r == rr) {
        tag[i] += v;
        mx[i] += v;
        return ;
    }
    if(r <= mid) update(ls,ll,mid,l,r,v);
    else if(l > mid) update(rs,mid+1,rr,l,r,v);
    else {
        update(ls,ll,mid,l,mid,v);
        update(rs,mid+1,rr,mid+1,r,v);
    }
    push_up(i);
}

int query(int i,int ll,int rr,int x) {
    push_down(i,ll,rr);
    if(ll == rr) return ll;
    if(mx[ls] == x) return query(ls,ll,mid,x);
    else return query(rs,mid+1,rr,x);
    push_up(i);
}
struct ss{
        int l,r,h,in;
        ss(int l = 0, int r = 0, int h = 0,int in = 0) : l(l), r(r), h(h),in(in) {}
        bool operator < (const ss & b) const {
            return h < b.h || h == b.h && in > b.in;
        }
}p[N],P[N];
int main() {
        scanf("%d",&n);
        for(int i = 1; i <= n; ++i) {
            int l,v,r;
            scanf("%d%d%d",&l,&v,&r);
            p[i] = ss(l,v,v,1);
            p[i+n] = ss(l,v,r,-1);
            P[i] = ss(l,r,v,1);
        }
        int m = n << 1;
        sort(p+1,p+m+1);
        int ans = 0,x,y;
        for(int i = 1; i <= m; ++i) {
            int l = p[i].l, r = p[i].r;
            update(1,1,300000,l,r,p[i].in);
            if(mx[1] > ans) {
                ans = mx[1];
                x = query(1,1,300000,mx[1]);
                y = p[i].h;
            }
        }
        printf("%d\n",ans);
        for(int i = 1; i <= n; ++i) {
            if(P[i].l <= x && P[i].r >= y && P[i].h >= x && P[i].h <= y) printf("%d\n",i);
        }
    return 0;
}
时间: 2024-10-13 01:44:27

Codeforces Round #222 (Div. 1) D. Developing Game 线段树有效区间合并的相关文章

Codeforces Round #271 (Div. 2) F.Ant colony(线段树 + 统计区间内某数的个数)

F. Ant colony Mole is hungry again. He found one ant colony, consisting of n ants, ordered in a row. Each ant i (1 ≤ i ≤ n) has a strength si. In order to make his dinner more interesting, Mole organizes a version of «Hunger Games» for the ants. He c

Codeforces Round #426 (Div. 2) D. The Bakery(线段树维护dp)

题目链接: Codeforces Round #426 (Div. 2) D. The Bakery 题意: 给你n个数,划分为k段,每段的价值为这一段不同的数的个数,问如何划分,使得价值最大. 题解: 考虑dp[i][j]表示划分为前j个数划分为i段的最大价值,那么这就是一个n*n*k的dp, 考虑转移方程dp[i][j]=max{dp[i][k]+val[k+1][j]},我们用线段树去维护这个max,线段树上每个节点维护的值是dp[i][k]+val[k+1][j],对于每加进来的一个数a

Codeforces Round #424 (Div. 2) E. Cards Sorting(线段树)

题目链接:Codeforces Round #424 (Div. 2) E. Cards Sorting 题意: 将n个数放进一个队列,每次检查队首,看看是不是队列中最小的数,如果是就扔掉,如果不是就放到队尾. 这样直到队列为空,为需要操作多少次. 题解: 考虑用两个指针模拟,最开始now指针指向第一个数,然后nxt指针指向下一个将要被删除的数. 然后我们要算出这里需要移动多少步,然后删掉这个数,一直重复操作,直到将全部的数删完. nxt指针可以用set来维护,now指针可以用并查集来维护. 计

Codeforces Round #603 (Div. 2) E. Editor(线段树)

链接: https://codeforces.com/contest/1263/problem/E 题意: The development of a text editor is a hard problem. You need to implement an extra module for brackets coloring in text. Your editor consists of a line with infinite length and cursor, which point

Codeforces Round #244 (Div. 2) B. Prison Transfer 线段树rmq

B. Prison Transfer Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/problemset/problem/427/B Description The prison of your city has n prisoners. As the prison can't accommodate all of them, the city mayor has decided to transfer c

Codeforces Round #275 Div.1 B Interesting Array --线段树

题意: 构造一个序列,满足m个形如:[l,r,c] 的条件. [l,r,c]表示[l,r]中的元素按位与(&)的和为c. 解法: 线段树维护,sum[rt]表示要满足到现在为止的条件时该子树的按位与和至少为多少. 更新时,如果val的pos位为1,那么整个区间的按位与和pos位也应该为1,否则与出来就不对了.(这是本题解题的核心) 那么此时更新 sum[rt] |= val 即可.然后再check一遍看是否满足所有条件即可. 代码: #include <iostream> #inclu

Codeforces Round #530 (Div. 2) E (树形dp+线段树)

链接: 题意: 给你一棵树,树上有n个节点,每个节点上有ai块饼干,在这个节点上的每块饼干需要花费bi时间,有两个玩家,玩家一可以移动到当前点的子节点也可以申请游戏结束返回根节点并吃沿途的饼干,玩家二可以删除当前点到儿子节点的一条边,走路和吃饼干都消耗时间,会给出一个总时间,在总时间内尽可能的多吃饼干,问最多能吃多少个? 思路: 由于是玩家一先手,那么最开始的最大边则不会被删除,但之后路途的最大边都会被玩家二删除,所以我们对于当前点我们需要求: 1.如果现在回头那么最多可以吃到多少饼干 2.向下

Codeforces Round #587 (Div. 3) F Wi-Fi(线段树+dp)

题意:给定一个字符串s 现在让你用最小的花费 覆盖所有区间 思路:dp[i]表示前i个全覆盖以后的花费 如果是0 我们只能直接加上当前位置的权值 否则 我们可以区间询问一下最小值 然后更新 #include <bits/stdc++.h> using namespace std; const int inf = 0x3f3f3f3f; const double eps = 1e-6; const int N = 2e5+7; typedef long long ll; const ll mod

Codeforces Round #470 (Div 2) B 数学 C 二分+树状数组 D 字典树

Codeforces Round #470 B. Primal Sport 数学题,对 x2 和 x1 分解质因子即可. #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a; i<=b; ++i) #define per(i,b,a) for (int i=b;