AtCoder Beginner Contest 186F Rook on Grid | Scan line, tree array

Originally, after ak, this atcoder wanted to write all the solutions, but the previous questions are really boring..

Just write this question.

Main idea:

Now there is an n*m matrix, the robot at the (1,1) position, it can move any square to the right or any square down (when there are no obstacles).

Now give k obstacles and ask how many points the robot can reach by moving at most twice

Question idea:

After the question is clear, an idea will naturally appear soon:

There are only two states for each point:

1. First move up to the first row, then move left to the first column

2. First move to the left to the first column, then move up to the first row

Since the range of n and m is too large, they cannot be enumerated. Consider using scan lines to solve this problem

Suppose a horizontal x scan line is scanned from the first row to the nth row, then for each row, consider the state of each point's movement

Set a position, if an obstacle appears in the first column of a certain row:

Then all the points below cannot be left and then right. Similarly, record the nearest point with obstacles in the first row. When the number of columns is greater than this, you cannot go up and then left.

So according to this nature:

1. If there is no obstacle with column number 1, then it means that you can go to the left at present, so if you find the first obstacle in the row, then all the grids on the left can be reached, and the grid on the right is Can only go up,

But while going up, you need to consider the relationship between the minimum number of columns in the first row and the current w

2. If there is currently an obstacle with a column number of 1, then it means that you can only go upwards, the same as above

Maybe a vis mark was added, and it was the fastest! ! !

Code:

/*** keep hungry and calm CoolGuang!  ***/
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define d(x) printf("%lld\n",x);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF= 1e17;
const ll maxn = 3e5+700;
const int mod= 1e9+7;
const int up = 1e9;
template<typename T>inline void read(T &a){char c=getchar();T x=0,f=1;while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
ll n,m,p;
ll h,w;
int vis[maxn];
int sum[maxn];
void add(int pos){
    while(pos<=w+1){
        sum[pos] ++;
        pos += pos&-pos;
    }
}
ll GetSum(int pos){
    ll ans = 0;
    while(pos){
        ans += sum[pos];
        pos -= pos&-pos;
    }return ans;
}
struct node{
    int x,y;
    bool friend operator<(node a,node b){
        return a.x < b.x;
    }
}q[maxn];
int main(){
    read(h);read(w);read(m);
    for(int i=1;i<=m;i++){
        read(q[i].x);
        read(q[i].y);
    }
    sort(q+1,q+1+m);
    int s = 1,f = 0,mi = w;
    ll ans = 0;
    for(int i=1;i<=h;i++){///扫描线
        int mx = w+1;
        while(s<=m&&q[s].x == i){
            mx = min(q[s].y,mx);
            if(q[s].x == 1) mi = min(mi,q[s].y);
            if(q[s].y == 1) f = 1;
            if(!vis[q[s].y]){
                add(q[s].y);
                vis[q[s].y] = 1;
            }
            s++;
        }
        if(f) ans += mi-GetSum(mi);
        else{
            ans += mx-1;
            if(mx <= mi) ans += mi-mx+1 - (GetSum(mi)-GetSum(mx-1));
        }
    }
    printf("%lld\n",ans);
    return 0;
}

/***
****/

 

Guess you like

Origin blog.csdn.net/qq_43857314/article/details/111476589