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:
- The 11-st row and the 22-nd row have a common 11 in the column 77.
- 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());
}
}