zoukankan      html  css  js  c++  java
  • Codeforces Round #737 (Div. 2) D. Ezzat and Grid DP+线段树优化

    Codeforces Round #737 (Div. 2) D. Ezzat and Grid DP+线段树优化

    题意

    给定(n)(m)列的01矩阵,删去若干行,使得结果矩阵满足任意相邻的两行存在某一列都是1

    要求输出删去的方案

    [1 leq n,mleq 3 imes 10^5\ 1 leq ileq n,1leq l leq r leq 10^9 ]

    分析

    比较明显的可以列出dp方程 (dp_i)表示以(i)为结尾的行的最多行数

    (dp[i] =1 + max{dp[j]},ij有共同1)

    这样难点就成为了难以判断(ij)是否有共同的1

    于是可以考虑

    [dp[i][j] = 1 + max{dp[i-1][j]} ,j in C_i ]

    这样实际上(dp)的含义就变掉了,相当于维护了前(i)行的max

    (C_i)表示第(i)行有1的列

    区间个数是(m)级别,因此(dp)的过程最多进行(O(m))次区间询问和更新

    这题的另一个难点是方案,这是比较套路的,可以在线段树上维护更新来的行数和path路径用于回溯

    代码

    #include<bits/stdc++.h>
    #define pii pair<ll,ll>
    #define fi first
    #define se second
    #define equals(a,b) (fabs(a-b) < 1e-8)
    using namespace std;
    typedef long long ll;
    
    
    inline ll rd(){
    	ll x = 0;
    	char ch = getchar();
    	while(ch < '0' || ch > '9'){
    		ch = getchar();
    	}
    	while(ch >= '0' && ch <= '9'){
    		x = x * 10 + ch - '0';
    		ch = getchar();
    	}
    	return x;
    }
    
    struct SegmentTree{
    	vector<pii> v;
    	vector<int> tag;
    	SegmentTree(int n):v((n + 1) << 2),tag((n + 1 )<< 2){}
    	inline void push_up(int i){
    		v[i] = max(v[i << 1],v[i << 1|1]);
    	}
    	inline void update(int i,pii val){
    		tag[i] = 1;
    		v[i] = val;
    	}
    	inline void push(int i){
    		if(tag[i]) {
    			update(i << 1,v[i]);
    			update(i << 1|1,v[i]);
    			tag[i] = 0;
    		}
    	}
    	void build(int i,int l,int r){
    		v[i] = make_pair(0,-1);
    		if(l == r)return;
    		int mid = l + r >> 1;
    		build(i << 1,l,mid);
    		build(i << 1|1,mid + 1,r);
    		push_up(i);
    	}
    	pii query(int i,int l,int r,int L,int R){
    		if(l > R || r < L) return make_pair(0,-1);
    		if(l >= L && r <= R) return v[i];
    		push(i);
    		int mid = l + r >> 1;
    		return max(query(i << 1,l,mid,L,R),query(i << 1|1,mid + 1,r,L,R));
    	}
    	void update(int i,int l,int r,int L,int R,pii val){
    		if(l > R || r < L) return;
    		if(l >= L && r <= R) return update(i,val);
    		int mid = l + r >> 1;
    		update(i << 1,l,mid,L,R,val);
    		update(i << 1|1,mid + 1,r,L,R,val);
    		push_up(i);
    	}
    };
    
    inline int get(int x,vector<int>&v){
    	return lower_bound(v.begin(),v.end(),x) - v.begin() + 1;
    }
    
    int main(){
    	int n = rd();
    	int m = rd();
    	vector<int> vis(n + 1);
    	vector<vector<pii>> lin(n + 1);
    	vector<int> vvv;
    	vector<int> path(n + 1);
    	for(int i = 1;i <= m;i++){
    		int R = rd();
    		int l = rd();
    		int r = rd();
    		lin[R].push_back(make_pair(l,r));
    		vvv.push_back(l);
    		vvv.push_back(r);
    	}
    	sort(vvv.begin(),vvv.end());
    	vvv.erase(unique(vvv.begin(),vvv.end()),vvv.end());
    	int N = vvv.size();
    	SegmentTree seg(N);
    	seg.build(1,1,N);
    	for(int i = 1;i <= n;i++){
    		for(auto &x:lin[i]){
    			x.fi = get(x.fi,vvv);
    			x.se = get(x.se,vvv);
    		}
    	}
    	for(int i = 1;i <= n;i++){
    		pii mx = make_pair(0,-1);
    		for(auto it:lin[i]) mx = max(mx,seg.query(1,1,N,it.fi,it.se));
    		path[i] = mx.se;
    		mx.fi++;
    		mx.se = i;
    		for(auto it:lin[i]) seg.update(1,1,N,it.fi,it.se,mx);
    	}
    	pii mx = seg.query(1,1,N,1,N);
    	int cur = mx.se;
    	int cnt = n;
    	while(cur != -1){
    		vis[cur] = 1;
    	   	cnt--;
    		cur = path[cur];	
    	}
    	printf("%d
    ",cnt);
    	for(int i = 1;i <= n;i++)
    		if(!vis[i]) printf("%d ",i);
    }
    
  • 相关阅读:
    css的三种方法以及优先级说明
    form表单中的label标签
    html 中 a 标签 mailto的用法
    Hexo + GitHub Pages搭建博客
    Sublime Text3使用指南
    IMU数据融合:互补,卡尔曼和Mahony滤波
    正点原子STM32探索者学习笔记4
    正点原子STM32探索者学习笔记3
    正点原子STM32探索者学习笔记2
    正点原子STM32探索者学习笔记1
  • 原文地址:https://www.cnblogs.com/hznumqf/p/15133178.html
Copyright © 2011-2022 走看看