杭电多校第四场补题
1. Lawn of the Dead
题意:
给出一个 n ⋅ m n \cdot m n⋅m 的网格,里面 k k k 个地雷,起点在 ( 1 , 1 ) (1,1) (1,1) ,从起点出发,不能经过地雷,求能达到的点有多少个?
n , m , k ≤ 1 e 5 n,m, k\leq 1e5 n,m,k≤1e5
题解:
因为 n , m n,m n,m很大,所以可以考虑从 k k k 入手。
考虑计算每行有多少个点能走。枚举行,对每行的地雷排序,地雷将一行分成了好几段,对每段分别求解。
因为每段的端点要么是边界,要么是地雷,所以要想走到这一段,只能从上一行的这一段往下走。怎么计算这一段能有多少个点能走呢?求出上一行这一段的最靠左的能走的点,那么从这个点下来然后向右走就是能走的最多的点。
最重要的就是维护出每行能走的点。可以使用线段树,构建两棵线段树,一棵维护上一行的信息,一棵维护当前行的信息,那么只需在上一行查找点,然后在当前行区间修改即可。
代码:
#pragma GCC diagnostic error "-std=c++11"
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<stack>
#include<set>
#include<ctime>
#define iss ios::sync_with_stdio(false)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int,int> pii;
const int mod=1e9+7;
const int MAXN=1e5+5;
const int inf=0x3f3f3f3f;
std::vector<int> g[MAXN];
struct node
{
    int l,r;
    int sum;
    int lazy;
}node[2][MAXN<<2];
void push_up(int id,int num){
    node[id][num].sum=node[id][num<<1].sum+node[id][num<<1|1].sum;
}
void push_down(int id,int num){
    if(node[id][num].lazy!=-1){
        node[id][num<<1].lazy=node[id][num<<1|1].lazy=node[id][num].lazy;
        node[id][num<<1].sum=(node[id][num<<1].r-node[id][num<<1].l+1)*node[id][num].lazy;
        node[id][num<<1|1].sum=(node[id][num<<1|1].r-node[id][num<<1|1].l+1)*node[id][num].lazy;
        node[id][num].lazy=-1;
    }
}
void build(int l,int r,int num){
    node[0][num].l=node[1][num].l=l;
    node[0][num].r=node[1][num].r=r;
    node[0][num].lazy=node[1][num].lazy=-1;
    node[0][num].sum=node[1][num].sum=0;
    if(l==r){
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,num<<1);
    build(mid+1,r,num<<1|1);
}
void updata(int id,int l,int r,int val,int num){
    if(node[id][num].l>=l&&node[id][num].r<=r){
        node[id][num].sum=(node[id][num].r-node[id][num].l+1)*val;
        node[id][num].lazy=val;
        return;
    }
    push_down(id,num);
    int mid=(node[id][num].l+node[id][num].r)>>1;
    if(l<=mid){
        updata(id,l,r,val,num<<1);
    }
    if(r>mid){
        updata(id,l,r,val,num<<1|1);
    }   
    push_up(id,num);
}
int query(int id,int l,int r,int num){
    if(node[id][num].l==node[id][num].r){
        return node[id][num].l;
    }
    push_down(id,num);
    int mid=(node[id][num].l+node[id][num].r)>>1;
    int sum1=node[id][num<<1].sum;
    int sum2=node[id][num<<1|1].sum;
    //cout<<sum1<<" "<<sum2<<" "<<l<<" "<<r<<" "<<node[id][num].l<<" "<<node[id][num].r<<endl;
    int pos=-1;
    if(sum1&&l<=mid){
        pos=query(id,l,r,num<<1);
    }
    if(sum2&&r>mid&&pos==-1){
        pos=query(id,l,r,num<<1|1);
    }
    return pos;
}   
int main()
{
    int t;
    scanf("%d",&t);
    while(t--){
        int n,m,k;
        scanf("%d%d%d",&n,&m,&k);
        for(int i=1;i<=k;i++){
            int x,y;
            scanf("%d%d",&x,&y);
            g[x].push_back(y);
        }
        build(1,m,1);
        updata(0,1,1,1,1);
        ll ans=0;
        for(int i=1;i<=n;i++){
            sort(g[i].begin(),g[i].end());
            int l=0;
            for(auto &r:g[i]){
                if(r-1>=l+1){
                    int pos=query((i&1)^1,l+1,r-1,1);
                    if(pos!=-1) updata(i&1,pos,r-1,1,1);
                    //cout<<i<<" "<<r<<" "<<pos<<endl;
                }
                l=r;
            }
            if(l+1<=m){
                int pos=query((i&1)^1,l+1,m,1);
                if(pos!=-1) updata(i&1,pos,m,1,1);
            }
            ans+=node[i&1][1].sum;
            updata((i&1)^1,1,m,0,1);
        }
        printf("%lld\n",ans);
        for(int i=1;i<=n;i++){
            g[i].clear();
        }
    }
}

 
                
             
         浙公网安备 33010602011771号
浙公网安备 33010602011771号