CF1557D. Ezzat and Grid(线段树离散化)

https://codeforces.com/contest/1557/problem/D

D. Ezzat and Grid

time limit per test

2.5 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

Moamen was drawing a grid of nn rows and 109109 columns containing only digits 00 and 11. Ezzat noticed what Moamen was drawing and became interested in the minimum number of rows one needs to remove to make the grid beautiful.

A grid is beautiful if and only if for every two consecutive rows there is at least one column containing 11 in these two rows.

Ezzat will give you the number of rows nn, and mm segments of the grid that contain digits 11. Every segment is represented with three integers ii, ll, and rr, where ii represents the row number, and ll and rr represent the first and the last column of the segment in that row.

For example, if n=3n=3, m=6m=6, and the segments are (1,1,1)(1,1,1), (1,7,8)(1,7,8), (2,7,7)(2,7,7), (2,15,15)(2,15,15), (3,1,1)(3,1,1), (3,15,15)(3,15,15), then the grid is:

Your task is to tell Ezzat the minimum number of rows that should be removed to make the grid beautiful.

Input

The first line contains two integers nn and mm (1≤n,m≤3⋅1051≤n,m≤3⋅105).

Each of the next mm lines contains three integers ii, ll, and rr (1≤i≤n1≤i≤n, 1≤l≤r≤1091≤l≤r≤109). Each of these mm lines means that row number ii contains digits 11 in columns from ll to rr, inclusive.

Note that the segments may overlap.

Output

In the first line, print a single integer kk — the minimum number of rows that should be removed.

In the second line print kk distinct integers r1,r2,…,rkr1,r2,…,rk, representing the rows that should be removed (1≤ri≤n1≤ri≤n), in any order.

If there are multiple answers, print any.

Examples

input

Copy

3 6
1 1 1
1 7 8
2 7 7
2 15 15
3 1 1
3 15 15

output

Copy

0

input

Copy

5 4
1 2 3
2 4 6
3 3 5
5 1 1

output

Copy

3
2 4 5

Note

In the first test case, the grid is the one explained in the problem statement. The grid has the following properties:

  1. The 11-st row and the 22-nd row have a common 11 in the column 77.
  2. The 22-nd row and the 33-rd row have a common 11 in the column 1515.

遍历每一行时,先取每一行对应列最大的值,再赋给其他列,还要维护一个前一行的路径。此题用离散化线段树,或线段树动态开点。线段树离散化效率比线段树效率高,线段数离散化能AC.

离散化思路是排序+二分,将值映射为下标。动态开点的思路是动态赋予左节点和右节点的顺序,但空间时间复杂度都较高。

import java.util.*;
import java.io.*;

public class Main {
    public static void main(String args[]) {new Main().run();}

    FastReader in = new FastReader();
    PrintWriter out = new PrintWriter(System.out);
    void run() {
        work();
        out.flush();
    }
    long mod=998244353;
    long gcd(long a,long b) {
        return a==0?b:gcd(b%a,a);
    }
    long inf=Long.MAX_VALUE/3;
    int[] num,numLazy,label,labelLazy,rc,lc;
    int maxn=600005;
    void work() {
        int n=ni(),m=ni();
        num=new int[maxn<<2];
        numLazy=new int[maxn<<2];
        label=new int[maxn<<2];
        labelLazy=new int[maxn<<2];
        Arrays.fill(label,-1);
        Arrays.fill(labelLazy,-1);
        int[][] A=new int[m][3];
        List<Integer> rec=new ArrayList<>();
        for(int i=0;i<m;i++){
            A[i]=new int[]{ni()-1,ni(),ni()};
            rec.add(A[i][1]);
            rec.add(A[i][2]);
        }
        Collections.sort(rec);
        Arrays.sort(A,(a1,a2)->a1[0]-a2[0]);
        int[] route=new int[n];
        for(int i=0,j=0;i<n;i++){
            List<int[]> list=new ArrayList<>();
            while(j<m&&A[j][0]==i){
                list.add(A[j]);
                j++;
            }
            if(list.size()==0)continue;
            int[] D=null;
            for(int[] B:list){
                int s=Collections.binarySearch(rec,B[1]);
                int e=Collections.binarySearch(rec,B[2]);
                int[] r1=query(1,s,e,0,maxn);
                if(D==null||D[0]<r1[0]){
                    D=r1;
                }
            }
            route[i]=D[1];
            for(int[] B:list){
                int s=Collections.binarySearch(rec,B[1]);
                int e=Collections.binarySearch(rec,B[2]);
                setVal(1,s,e,0,maxn,D[0]+1,i);
            }
        }
        int[] r1=query(1,0,maxn,0,maxn);
        int cur=r1[1];
        out.println(n-r1[0]);
        boolean[] vis=new boolean[n];
        while(cur!=-1){
            vis[cur]=true;
            cur=route[cur];
        }
        for(int i=0;i<n;i++){
            if(!vis[i]){
                out.print((i+1)+" ");
            }
        }
    }

    private void setVal(int node, int s, int e, int l, int r, int v,int idx) {
        if(s<=l&&r<=e){
            num[node]=v;
            numLazy[node]=v;
            label[node]=idx;
            labelLazy[node]=idx;
            return;
        }
        pushUp(node);
        int m=(l+r)/2;
        if(s<=m){
            setVal(node<<1,s,e,l,m,v,idx);
        }
        if(e>=m+1){
            setVal(node<<1|1,s,e,m+1,r,v,idx);
        }
        if(num[node<<1]>num[node<<1|1]){
            num[node]=num[node<<1];
            label[node]=label[node<<1];
        }else{
            num[node]=num[node<<1|1];
            label[node]=label[node<<1|1];
        }
    }

    private int[] query(int node, int s, int e, int l, int r) {
        if(s<=l&&r<=e){
            return new int[]{num[node],label[node]};
        }
        pushUp(node);
        int m=(l+r)/2;
        int[] ret=null;
        if(s<=m){
            ret=query(node<<1,s,e,l,m);
        }
        if(e>=m+1){
            int[] D=query(node<<1|1,s,e,m+1,r);
            if(ret==null||D[0]>ret[0]){
                ret=D;
            }
        }
        return ret;
    }

    private void pushUp(int node) {
        if(labelLazy[node]!=-1){
            label[node<<1|1]=labelLazy[node];
            labelLazy[node<<1|1]=labelLazy[node];
            label[node<<1]=labelLazy[node];
            labelLazy[node<<1]=labelLazy[node];
            labelLazy[node]=-1;
        }
        if(numLazy[node]!=0){
            num[node<<1|1]=numLazy[node];
            numLazy[node<<1|1]=numLazy[node];
            num[node<<1]=num[node];
            numLazy[node<<1]=numLazy[node];
            numLazy[node]=0;
        }
    }

    @SuppressWarnings("unused")
    private ArrayList<Integer>[] ng(int n, int m) {
        ArrayList<Integer>[] graph=(ArrayList<Integer>[])new ArrayList[n];
        for(int i=0;i<n;i++) {
            graph[i]=new ArrayList<>();
        }
        for(int i=1;i<=m;i++) {
            int s=in.nextInt()-1,e=in.nextInt()-1;
            graph[s].add(e);
            graph[e].add(s);
        }
        return graph;
    }

    private ArrayList<long[]>[] ngw(int n, int m) {
        ArrayList<long[]>[] graph=(ArrayList<long[]>[])new ArrayList[n];
        for(int i=0;i<n;i++) {
            graph[i]=new ArrayList<>();
        }
        for(int i=1;i<=m;i++) {
            long s=in.nextLong()-1,e=in.nextLong()-1,w=in.nextLong();
            graph[(int)s].add(new long[] {e,w});
            graph[(int)e].add(new long[] {s,w});
        }
        return graph;
    }

    private int ni() {
        return in.nextInt();
    }

    private long nl() {
        return in.nextLong();
    }
    private double nd() {
        return in.nextDouble();
    }
    private String ns() {
        return in.next();
    }

    private long[] na(int n) {
        long[] A=new long[n];
        for(int i=0;i<n;i++) {
            A[i]=in.nextLong();
        }
        return A;
    }

    private int[] nia(int n) {
        int[] A=new int[n];
        for(int i=0;i<n;i++) {
            A[i]=in.nextInt();
        }
        return A;
    }
}

class FastReader
{
    BufferedReader br;
    StringTokenizer st;
    InputStreamReader input;//no buffer
    public FastReader()
    {
        br=new BufferedReader(new InputStreamReader(System.in));
    }

    public FastReader(boolean isBuffer)
    {
        if(!isBuffer){
            input=new InputStreamReader(System.in);
        }else{
            br=new BufferedReader(new InputStreamReader(System.in));
        }
    }

    public boolean hasNext(){
        try{
            String s=br.readLine();
            if(s==null){
                return  false;
            }
            st=new StringTokenizer(s);
        }catch(IOException e){
            e.printStackTrace();
        }
        return true;
    }

    public String next()
    {   
        if(input!=null){
            try {
                StringBuilder sb=new StringBuilder();
                int ch=input.read();
                while(ch=='\n'||ch=='\r'||ch==32){
                    ch=input.read();
                }
                while(ch!='\n'&&ch!='\r'&&ch!=32){
                    sb.append((char)ch);
                    ch=input.read();
                }
                return sb.toString();
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        while(st==null || !st.hasMoreElements())//回车,空行情况
        {
            try {
                st = new StringTokenizer(br.readLine());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return st.nextToken();
    }

    public int nextInt()
    {
        return (int)nextLong();
    }

    public long nextLong() {
        try {
            if(input!=null){
                long ret=0;
                int b=input.read();
                while(b<'0'||b>'9'){
                    b=input.read();
                }
                while(b>='0'&&b<='9'){
                    ret=ret*10+(b-'0');
                    b=input.read();
                }
                return ret;
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return Long.parseLong(next());
    }

    public double nextDouble()
    {
        return Double.parseDouble(next());
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值