1. 程式人生 > >【codeforces】480E Parking Lot 線段樹+DP

【codeforces】480E Parking Lot 線段樹+DP


題目分析:很早以前在同學助攻下寫出來的,想想還是放出來好了,是個不錯的思想。

原題是在動態將可行區域變成不可行區域的同時求全域性最大子正方形,n,m,k至多2000。

既然只有加點,於是我們離線,倒著來,這樣便只有刪點。

我們給每個節點(i,j)儲存它向上能延伸的距離U[i][j]以及向下能延伸的距離D[i][j]。

易知刪除一個點最多影響一列上的U和D,暴力更新U,D。複雜度為O(n^2),可以承受。

首先我們預處理出所有點都加上後的最大子正方形(直接dp)。

然後建立一棵線段樹,線段樹儲存一段區間向下延伸的最大子矩形的高度(即最小的D),同時儲存一段區間向上延伸的最大子矩形的高度(即最小的U)。

每次刪點時我們暴力維護U,D,然後對刪點的那一行建立線段樹進行最大子正方形大小的維護(最大子正方形大小的改變一定和這一行上的點有關)。

維護方法直接見程式碼好了。

然後查詢就是O(1)的操作了。

覺得這解題的思想很不錯,值得思考~

而且這題的解法貌似很多的樣子。。

程式碼如下:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std ;

typedef long long LL ;

#define rep( i , a , b ) for ( int i = a ; i < b ; ++ i )
#define For( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define rev( i , a , b ) for ( int i = a ; i >= b ; -- i )
#define clr( a , x ) memset ( a , x , sizeof a )
#define ls ( o << 1 )
#define rs ( o << 1 | 1 )
#define lson ls , l , m
#define rson rs , m + 1 , r
#define mid ( ( l + r ) >> 1 )
#define root 1 , 1 , m

const int MAXN = 2005 ;
const int INF = 0x3f3f3f3f ;

struct Node {
	int x , y ;
} p[MAXN] ;

int minu[MAXN << 2] , mind[MAXN << 2] ;
int G[MAXN][MAXN] ;
int U[MAXN][MAXN] ;
int D[MAXN][MAXN] ;
int left[MAXN] , right[MAXN] ;
int ans[MAXN] ;
int n , m , k ;

int min1 , min2 ;
void query ( int L , int R , int o , int l , int r ) {
	if ( L <= l && r <= R ) {
		min1 = min ( min1 , minu[o] ) ;
		min2 = min ( min2 , mind[o] ) ;
		return ;
	}
	int m = mid ;
	if ( L <= m ) query ( L , R , lson ) ;
	if ( m <  R ) query ( L , R , rson ) ;
}

void build ( int x , int o , int l , int r ) {
	if ( l == r ) {
		minu[o] = U[x][l] ;
		mind[o] = D[x][l] ;
		return ;
	}
	int m = mid ;
	build ( x , lson ) ;
	build ( x , rson ) ;
	minu[o] = min ( minu[ls] , minu[rs] ) ;
	mind[o] = min ( mind[ls] , mind[rs] ) ;
}

int calc () {
	int ans = 0 ;
	For ( i , 1 , n ) {
		For ( j , 1 , m ) {
			int x = j ;
			while ( x > 1 && U[i][x - 1] >= U[i][j] ) x = left[x - 1] ;
			left[j] = x ;
		}
		rev ( j , m , 1 ) {
			int x = j ;
			while ( x < m && U[i][x + 1] >= U[i][j] ) x = right[x + 1] ;
			right[j] = x ;
		}
		For ( j , 1 , m ) {
			ans = max ( ans , min ( U[i][j] , right[j] - left[j] + 1 ) ) ;
			//printf ( "%d %d %d\n" , U[i][j] , left[j] , right[j] ) ;
		}
		//printf ( "%d\n" , ans ) ;
	}
	return ans ;
}

int check ( int size , int y ) {
	if ( size > n || size > m ) return 0 ;
	For ( i , max ( 1 , y - size + 1 ) , m - size + 1 ) {
		min1 = min2 = INF ;
		query ( i , i + size - 1 , root ) ;
		if ( min1 + min2 - 1 >= size ) return 1 ;
	}
	return 0 ;
}

void solve () {
	clr ( U , 0 ) ;
	clr ( D , 0 ) ;
	clr ( G , 0 ) ;
	clr ( ans , 0 ) ;
	For ( i , 1 , n ) {
		getchar () ;
		For ( j , 1 , m ) {
			char c = getchar () ;
			G[i][j] = c == '.' ;
		}
	}
	rep ( i , 0 , k ) {
		scanf ( "%d%d" , &p[i].x , &p[i].y ) ;
		G[p[i].x][p[i].y] = 0 ;
	}
	//For ( i , 1 , n ) For ( j , 1 , m ) printf ( "%d%c" , G[i][j] , j < m ? ' ' : '\n' ) ;
	For ( i , 1 , n ) For ( j , 1 , m ) U[i][j] = G[i][j] ? U[i - 1][j] + 1 : 0 ;
	rev ( i , n , 1 ) For ( j , 1 , m ) D[i][j] = G[i][j] ? D[i + 1][j] + 1 : 0 ;
	int size = calc () ;
	rev ( i , k - 1 , 0 ) {
		ans[i] = size ;
		if ( !i ) break ;
		int x = p[i].x ;
		int y = p[i].y ;
		G[x][y] = 1 ;
		U[x][y] = U[x - 1][y] + 1 ;
		For ( j , x + 1 , n ) {
			if ( !G[j][y] ) break ;
			U[j][y] += U[x][y] ;
		}
		D[x][y] = D[x + 1][y] + 1 ;
		rev ( j , x - 1 , 1 ) {
			if ( !G[j][y] ) break ;
			D[j][y] += D[x][y] ;
		}
		build ( x , root ) ;
		while ( check ( size + 1 , y ) ) ++ size ;
	}
	rep ( i , 0 , k ) printf ( "%d\n" , ans[i] ) ;
}

int main () {
	while ( ~scanf ( "%d%d%d" , &n , &m , &k ) ) solve () ;
	return 0 ;
}


相關推薦

codeforces480E Parking Lot 線段+DP

題目分析:很早以前在同學助攻下寫出來的,想想還是放出來好了,是個不錯的思想。 原題是在動態將可行區域變成不可行區域的同時求全域性最大子正方形,n,m,k至多2000。 既然只有加點,於是我們離線,倒著來,這樣便只有刪點。 我們給每個節點(i,j)儲存它向上能延伸的距

codeforces480E Parking Lot

#include <stdio.h> #include <algorithm> #include <string.h> #define rep(ii,a,b) for (int ii=(a);ii<=(b);ii++) #defin

BZOJ4869相逢是問候 [線段]

lib 替換 rip input 次方 一行 event bfc 同時 相逢是問候 Time Limit: 40 Sec Memory Limit: 512 MB[Submit][Status][Discuss] Description   Informat

BZOJ4825[Hnoi2017]單旋 線段+set

http src end 發生 升序 root getc sin 技能 【BZOJ4825】[Hnoi2017]單旋 Description H 國是一個熱愛寫代碼的國家,那裏的人們很小去學校學習寫各種各樣的數據結構。伸展樹(splay)是一種數據結構,因為代碼好寫

BZOJ2752[HAOI2012]高速公路(road) 線段

有道 開車 const 數據 給定 family 重要 mes 標準 【BZOJ2752】[HAOI2012]高速公路(road) Description Y901高速公路是一條重要的交通紐帶,政府部門建設初期的投入以及使用期間的養護費用都不低,因此政府在這條高速公

BZOJ4388JOI2012 invitation 堆+線段+並查集模擬Prim

每次 ros ins 一場 flag uil heap clu 一個點 【BZOJ4388】JOI2012 invitation Description 澳洲猴舉辦了一場宴會,他想要邀請A個男生和B個女生參加,這A個男生從1到A編號,女生也從1到B編號。現在澳洲猴知

BZOJ4262Sum 單調棧+線段

技術分享 strong lin getchar() 上一個 highlight 線段樹 put ron 【BZOJ4262】Sum Description Input 第一行一個數 t,表示詢問組數。 第一行一個數 t,表示詢問組數。 接下來 t

CF875EDelivery Club 二分+線段

names turn body sort mod pri esp string etc 【CF875E】Delivery Club 題意:有n個快遞需要依次接收,這n個快遞分部在x軸上,第i個快遞的位置是xi。有兩個快遞員,一開始分別在s0,s1,你可以任意安排哪個人收哪

bzoj5123[Lydsy12月賽]線段的匹配 樹形dp+記憶化搜索

記憶 兩種 spa post mes efi http 搜索 style 題目描述 求一棵 $[1,n]$ 的線段樹的最大匹配數目與方案數。 $n\le 10^{18}$ 題解 樹形dp+記憶化搜索 設 $f[l][r]$ 表示根節點為 $[l,r]$ 的線段

bzoj3747Kinoman[POI2015](線段

def online else sin time line code 最大的 splay   題目傳送門:http://www.lydsy.com/JudgeOnline/problem.php?id=3747   對於這種題,考慮固定區間的右端點為r,設區間左端點為l能

bzoj4355Play with sequence 線段區間最值操作

max ans 時間 query sam define sca tps fine 題目描述 維護一個長度為N的序列a,現在有三種操作: 1)給出參數U,V,C,將a[U],a[U+1],...,a[V-1],a[V]都賦值為C。 2)給出參數U,V,C,對於區間[U,

XSY2732Decalcomania 可持久化線段 分治

lin %d == void ret 多少 for size include 題目描述   有一個陶瓷瓶周圍有\(n\)個可以印花的位置。第\(i\)個與第\(i+1\)個位置之間的距離為\(d_i\),在第\(i\)個位置印圖案要\(t_i\)秒。   機器剛開始在\(0

CF687DDividing Kingdom II 線段+並查集

三種 for uil tro log std 從大到小 typedef 證明 【CF687D】Dividing Kingdom II 題意:給你一張n個點m條邊的無向圖,邊有邊權$w_i$。有q個詢問,每次給出l r,問你:如果只保留編號在[l,r]中的邊,你需要將所有點

BZOJ4311: 向量(線段分治板子題)

char 給定 dot 區間 int() str friend 所有 bre 題解 我們可以根據點積的定義,垂直於原點到給定點構成的直線作一條直線,從正無窮往下平移,第一個碰到的點就是答案 像什麽,上凸殼哇 可是……動態維護上凸殼? 我們可以離線,計算每個點能造成貢獻的一個

BZOJ5334數學計算(線段

names efi stream lin ++ show print get http 【BZOJ5334】數學計算(線段樹) 題面 BZOJ 洛谷 題解 簡單的線段樹模板題??? 咕咕咕。 #include<iostream> #include<cstd

BZOJ4025二分圖(線段分治,並查集)

math namespace struct modify push clas str clu php 【BZOJ4025】二分圖(線段樹分治,並查集) 題面 BZOJ 題解 是一個二分圖,等價於不存在奇環。 那麽直接線段樹分治,用並查集維護到達根節點的距離,只計算就好了。

GDKOI2018 魔卡少女 線段

color print %d node () .... code space for 題目大意:給你一個長度為n的序列${a_1....a_n}$,有$m$次操作 每次操作有兩種情況:修改$a_i$的值,詢問$[l,r]$中所有子區間的異或和。 數據範圍:$n,m&le

題解poj3171 Cleaning Shifts 線段優化DP

題目連結 Description Farmer John’s cows, pampered since birth, have reached new heights of fastidiousness. They now require their barn

2018.10.08AHOI2009洛谷P2023BZOJ1798維護序列(線段

洛谷傳送門 解析: 由於乘法的優先順序大於加法,我們考慮以乘法為主維護(就是儘量不去動乘法的延遲標記)。 維護方式如下: 1.遇到加法,直接加在加法標記上,並更新當前數列的和。 2.遇到乘法,同時更新乘法標記,加法標記,當前序列和。 3.下傳標記時,先傳乘法