补题,杭电第四场
题目:Lawn of the Dead
大意就是说有一个地图大小为n*m;
其中有k个地雷位置,玩家从地图的(1,1)位置开始走
只能向右走或者是向下走。问能走的位置有多少个。
就图中的例子来说
红色的为地雷的位置,黑色的为无法走到位置所以一共有4*4-6=10个位置可以走到输出10
最简单方法就是做一个图,查询每个点的左边和上面是不是不可访问区域,是就将该点也改为不可访问点,最后所有的点减去不可访问的点就是可访问的点。
简单点的做法如下:
#include<iostream>
#include<cstring>
using namespace std;
#define Max 10010
int **Map;
//int Map[Max][Max];
int main()
{
int N;
cin>>N;
while(N--)
{
int n,m,k;
cin>>n>>m>>k;
Map=new int *[n];
for(int i=0;i<=n;i++)
Map[i]=new int [m+1];
for(int i=0;i<=n;i++)
{
for(int j=0;j<=m;j++)
Map[i][j]=-1;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
Map[i][j]=1;
}
int x,y;
for(int i=0;i<k;i++)
{
cin>>x>>y;
Map[x][y]=-1;
}
int no_ans=0;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(i==1&&j==1)
continue;
if((Map[i-1][j]==-1 && Map[i][j-1]==-1) || Map[i][j]==-1)
{
no_ans++;
Map[i][j]=-1;
}cout<<Map[i][j]<<" ";
}
cout<<endl;
}
cout<<n*m-no_ans<<endl;
}
}
不过由于n,m,的范围为10^5所以要用另一种方法。
可以发现,不可访问点只跟上一行的地雷位置有关,所以当一个地雷的右上角位置所连续的地雷范围,在这一行也是无法走到的,例如:
红色的是雷,那么下面一行的黑色横线部分是无法通过的。
所以可以先对雷点进行排序,然后用线段树进行区间的查询和修改,可以节约空间。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define INF_int 0x3f3f3f3f;
#define maxn 1e5+3;
#define ls (rt<<1)
#define rs ((rt<<1)|1)
int n, m, k;
vector<int>vec[maxn];
struct tree {
int l, r;
int lazy;
int sum;
}tr[2][maxn];
void pushup(int op, int rt) {
tr[op][rt].sum = tr[op][ls].sum + tr[op][rs].sum;
}
void solve(int op, int rt, int val) {
tr[op][rt].sum = (tr[op][rt].r - tr[op][rt].l + 1)*val;
tr[op][rt].lazy = val;
}
void pushdown(int op, int rt) {
solve(op, ls, tr[op][rt].lazy);
solve(op, rs, tr[op][rt].lazy);
tr[op][rt].lazy = -1;
}
void build(int op, int rt, int l, int r) {
tr[op][rt].l = l;
tr[op][rt].r = r;
if (l == r) {
tr[op][rt].sum = 0;
tr[op][rt].lazy = -1;
return;
}
int mid = r >> 1+1;
build(op, ls, l, mid);
build(op, rs, mid + 1, r);
pushup(op, rt);
}
void update(int op, int rt, int L, int R, int v) {
if (L > tr[op][rt].r || R < tr[op][rt].l)return;
if (L <= tr[op][rt].l&&tr[op][rt].r <= R) {
solve(op, rt, v);
return;
}
if (tr[op][rt].lazy != -1)pushdown(op, rt);
update(op, ls, L, R, v);
update(op, rs, L, R, v);
pushup(op, rt);
}
int query(int op, int rt, int L, int R) {
if (!tr[op][rt].sum)return INF_int;
if (L > tr[op][rt].r || R < tr[op][rt].l)return INF_int;
if (tr[op][rt].l == tr[op][rt].r)return tr[op][rt].l;
if (tr[op][rt].lazy != -1)
pushdown(op, rt);
if (L <= tr[op][rt].l&&tr[op][rt].r <= R) {
if (tr[op][ls].sum > 0)return query(op, ls, L, R);
else return query(op, rs, L, R);
}
return min(query(op, ls, L, R), query(op, rs, L, R));
}
void init() {
for (int i = 1; i <= n; i++)vec[i].clear();
memset(tr, 0, sizeof(tr));
}
int main()
{
int T;
cin >> T;
while (T--) {
cin >> n >> m >> k;
init();
for (int i = 1; i <= k; i++) {
int x, y;
cin >> x >> y;
vec[x].push_back(y);
}
build(0, 1, 1, m);
build(1, 1, 1, m);
update(1, 1, 1, 1, 1);
int op = 0;
ll ans = 0;
for (int i = 1; i <= n; i++) {
int L = 0;
sort(vec[i].begin(), vec[i].end());
int pos;
for (int y : vec[i]) {
if (y - 1 >= L + 1)
{
pos = query(op ^ 1, 1, L + 1, y - 1);
if (pos != INF_int)
update(op, 1, pos, y - 1, 1);
}
L = y;
}
if (L + 1 <= m) {
pos = query(op ^ 1, 1, L + 1, m);
if (pos != INF_int)
update(op, 1, pos, m, 1);
}
ans += tr[op][1].sum;
update(op ^ 1, 1, 1, m, 0);
op ^= 1;
}
cout << ans << endl;
}
return 0;
}