Lawn of the Dead——杭电第四场 1008

Lawn of the Dead

HDU6992

题目描述

题目给出一个 \(n*m\) 的网格,和 \(k\)个地雷的位置,你从 \((1,1)\) 出发只能向右或者向下走,并且不能经过地雷区,可以到达的最大网格数是多少。

解题思路

首先我们可以把每一行的地雷位置存起来,然后从上到下遍历 \(n\)行,维护 \(1-m\) 的区间里可走的位置,即可达置 \(1\),不可达置 \(0\)
当考虑第 \(i\) 行时,遍历这一行的地雷位置,如果当前地雷位置为 \(j\),我们只需要知道 \([pre+1,j-1]\) (\(pre\) 为这一行上一个地雷的位置)区间内第一个可达的位置 \(pos\),然后就可以将 \([pos,j-1]\)这个区间全置 \(1\)即可,遍历结束后答案加上这行的 \(1\)的数量。
注意到当前行的状态只受到上一行的影响,所以可以开两个线段树,使用滚动数组来维护。
最后注意的是初始化需要将第 \(0\) 行的位置\(1\)置为\(1\),即可达状态。

Code

#include <bits/stdc++.h>
#define ll long long
#define qc ios::sync_with_stdio(false); cin.tie(0);cout.tie(0)
#define fi first
#define se second
#define PII pair<int, int>
#define PLL pair<ll, ll>
#define pb push_back
#define V vector
using namespace std;
const int N = 2e5 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 1e9 + 7;
inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
	return x*f;
}
int tree[N<<2][2], lz[N<<2][2];
void pushup(int f,int rt){
	tree[rt][f] = tree[rt<<1][f] + tree[rt<<1|1][f]; 
}
void pushdown(int f,int rt,int l,int r){
	if(lz[rt][f] != -1){
		int mid = (l + r) >> 1;
		tree[rt<<1][f] = (mid - l + 1) * lz[rt][f];
		lz[rt<<1][f] = lz[rt][f];
		tree[rt<<1|1][f] = (r - mid) * lz[rt][f];
		lz[rt<<1|1][f] = lz[rt][f];
		lz[rt][f] = -1;
	}
}
void update(int f,int x,int l,int r,int L,int R,int rt){
	if(L <= l && r <= R){
		tree[rt][f] = (r - l + 1) * x;
		lz[rt][f] = x;
		return;
	}
	pushdown(f,rt,l,r);
	int mid = (l + r) >> 1;
	if(L <= mid)update(f,x,l,mid,L,R,rt<<1);
	if(mid < R)update(f,x,mid+1,r,L,R,rt<<1|1);
	pushup(f,rt);
}
int query(int f,int l,int r,int L,int R,int rt){
	if(!tree[rt][f])return inf;
	if(l == r)return l;
	pushdown(f,rt,l,r);
	int mid = (l + r) >> 1;
	if(L <= l && r <= R){
		if(tree[rt<<1][f])return query(f,l,mid,L,R,rt<<1);
		else return query(f,mid+1,r,L,R,rt<<1|1);
	}else{
		int res = inf;
		if(mid >= L)res = min(res, query(f,l,mid,L,R,rt<<1));
		if(mid < R)res = min(res, query(f,mid+1,r,L,R,rt<<1|1));
		return res;
	}
}
V<int>v[N];
void solve(){
	int n,m,k;
	cin >> n >> m >> k;
	ll ans = 0;
	for(int i = 0; i <= (m << 2); i++){
		tree[i][0] = tree[i][1] = 0;
		lz[i][0] = lz[i][1] = -1;
	}
	for(int i = 1; i <= k; i++){
		int x,y;
		cin >> x >> y;
		v[x].pb(y);
	}
	for(int i = 1; i <= n; i++)
		sort(v[i].begin(),v[i].end());
	update(0,1,1,m,1,1,1);
	for(int i = 1; i <= n; i++){
		int l = 0;
		for(int j : v[i]){
			if(l + 1 <= j - 1){
				int pos = query((i & 1) ^ 1,1,m,l+1,j-1,1);
				if(pos != inf)update((i & 1), 1, 1, m, pos, j - 1, 1);
			}
			l = j;
		}
		if(l + 1 <= m){
			int pos = query((i & 1) ^ 1,1,m,l+1,m,1);
			if(pos != inf)update((i & 1), 1, 1, m, pos, m, 1);
		}
		ans += tree[1][i & 1];
		update((i & 1) ^ 1, 0, 1, m, 1, m, 1);
	}
	cout << ans << "\n";
	for(int i = 1; i <= n; i++)
		v[i].clear();
}

int main()
{
	#ifdef ONLINE_JUDGE
	#else
		freopen("in.txt", "r", stdin);
		freopen("out.txt", "w", stdout);
	#endif

	qc;
	int T = 1;
	cin >> T;
	while(T--){
		solve();
	}
	return 0;
}

posted @ 2021-08-30 21:19  !^^!  阅读(52)  评论(0编辑  收藏  举报