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;
}
Code will change the world !