Lawn of the Dead (线段树)

传送门

给定一个n*m的网格,有k个地雷,不能踩到地雷所在格子,从(1,1)出发,只能往左或者往下走,问最多可以到达多少个格子。

由于n,m都是1e5级别,所以我们不能模拟。

我们先观察一个结论,

  • 对于第i行,假设有y1,y2两个雷,[y1+1,y2-1]这个区间格子如何能被到达呢?

  • 只能从上面下来,所以我们在第i-1行中找到[y1+1,y2-1]这个区间内最左端的可到达的位置idx,那么我们从第i-1行的idx列走下来到达第i行的idx列,所以第i行的[idx,y2-1]这个区间都是可到达的了。

  • 如果我们用1代表可到达,0代表不可到达,上面的操作实质就是区间查询,区间覆盖,最后每行的答案就是查询区间和,每行答案累加起来就是最终答案。(除了维护区间和之外,还需要额外维护区间内最左端1的位置)

  • 我们考虑对每行都建一个线段树,但是空间不够,我们可以只建两棵,用滚动数组的思想。每次滚动都把区间更新成全是0的情况。

  • 枚举到第i行时,每次先假设第i行都是0 ([1,m]的区间覆盖),然后枚举地雷进行区间更新

  • 细节:1、第一行需要特判。2、我们可以假设第0列,第m+1列都是雷,这样可以省略很多特殊情况的判断

#include<bits/stdc++.h>
using namespace std;
//#pragma GCC optimize(2)
#define ull unsigned long long
#define ll long long
#define pii pair<int, int>
const int maxn = 1e5 + 10;
const ll mod = 998244353;
const ll inf = (ll)4e16+5;
const int INF = 1e9 + 7;
const double pi = acos(-1.0);
ll inv(ll b){if(b==1)return 1;return(mod-mod/b)*inv(mod%b)%mod;}
inline ll read()
{
    ll x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
struct node 
{
    #define lc rt<<1
    #define rc rt<<1|1
    int l,r;
    int idx;//最小的 1所在的列 没有1则记为m+1 1表示可以走
    int sum;//区间和  表示可以走的格子数 每结束一行 求一次区间和 累加答案 
}tree[2][maxn<<2];
int tag[2][maxn<<2];//区间覆盖的lazy 1表示覆盖成1  2表示覆盖成0
int n,m,q;
inline void pushup(int rt,int k) 
{
    tree[k][rt].sum=tree[k][lc].sum + tree[k][rc].sum;
    tree[k][rt].idx=min(tree[k][lc].idx , tree[k][rc].idx);
}
void build(int rt,int l,int r,int k)//刚开始假设全部不能走
{
    tree[k][rt].l=l,tree[k][rt].r=r;
    tag[k][rt]=0;
    if(l==r)
    {
        tree[k][rt].idx=m+1;
        tree[k][rt].sum=0;
        return ;
    }
    int mid=l+r>>1;
    build(lc,l,mid,k);build(rc,mid+1,r,k);
    pushup(rt,k);
}
inline void change(int rt,int v,int k)
{
    tree[k][rt].sum=(tree[k][rt].r-tree[k][rt].l+1)*(v%2);
    if(!tree[k][rt].sum) 
    {
        tree[k][rt].idx=m+1;
    }
    else tree[k][rt].idx=tree[k][rt].l;
    tag[k][rt]=v;
}
inline void pushdown(int rt,int k)
{
    if(tag[k][rt]) 
    {
        change(lc,tag[k][rt],k);
        change(rc,tag[k][rt],k);
        tag[k][rt]=0;
    }
}
void upd(int rt,int vl,int vr,int v,int k)
{
    int l=tree[k][rt].l,r=tree[k][rt].r;
    if(vr<l || vl>r || vr<vl) return ;
    if(vl<=l && r<=vr) 
    {
        change(rt,v,k);
        return ;
    }
    pushdown(rt,k);
    upd(lc,vl,vr,v,k);
    upd(rc,vl,vr,v,k);
    pushup(rt,k);
}
int qry(int rt,int vl,int vr,int k)
{
    int l=tree[k][rt].l,r=tree[k][rt].r;
    if(vr<l || vl>r || vr<vl) return m+1;
    if(vl<=l && r<=vr) 
    {
        return tree[k][rt].idx;
    }
    pushdown(rt,k);
    return min(qry(lc,vl,vr,k) , qry(rc,vl,vr,k));
}
int qry1(int rt,int vl,int vr,int k)
{
    int l=tree[k][rt].l,r=tree[k][rt].r;
    if(vr<l || vl>r || vr<vl) return 0;
    if(vl<=l && r<=vr) 
    {
        return tree[k][rt].sum;
    }
    pushdown(rt,k);
    return qry(lc,vl,vr,k) + qry(rc,vl,vr,k);
}
vector<int> dead[maxn];
int main()
{
    int t;cin>>t;
    while(t--)
    {
        scanf("%d %d %d",&n,&m,&q);
        for(int i=0;i<=n+1;i++) dead[i].clear();
        for(int i=1,x,y;i<=q;i++)
        {
            scanf("%d %d",&x,&y);
            dead[x].push_back(y);
        }
        //不妨假设第0列 m+1列 全是雷
        for(int i=1;i<=n;i++) 
        {
            dead[i].push_back(0);
            dead[i].push_back(m+1);
            sort(dead[i].begin(),dead[i].end());
        }

        build(1,1,m,1);//建树
        build(1,1,m,0);
        ll ans=0;
        //特判第一行
        if((int)dead[1].size() == 2) //除0 m+1列外没有雷
        {
            upd(1,1,m,1,1);
        }
        else upd(1,1,dead[1][1]-1,1,1);//1到第一个雷前一格的这段区间 可以走
        ans+=qry1(1,1,m,1);

        for(int i=2;i<=n;i++)
        {
            upd(1,1,m,2,i%2);//滚动数组 先假设这一行全不能走
            for(int j=0;j<(int)dead[i].size()-1;j++)
            {
                int y1=dead[i][j],y2=dead[i][j+1];
                //第i-1行的线段树中 查询[y1+1,y2-1]区间内 最左端的1
                int left=qry(1,y1+1,y2-1,(i-1)%2);
                if(left == m+1) continue;//都是0
                upd(1,left,y2-1,1,i%2);
            }
            ans+=qry1(1,1,m,i%2);
        }
        printf("%lld\n",ans);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1444. Elephpotamus Time limit: 0.5 second Memory limit: 64 MB Harry Potter is taking an examination in Care for Magical Creatures. His task is to feed a dwarf elephpotamus. Harry remembers that elephpotamuses are very straightforward and imperturbable. In fact, they are so straightforward that always move along a straight line and they are so imperturbable that only move when attracted by something really tasty. In addition, if an elephpotamus stumbles into a chain of its own footprints, it falls into a stupor and refuses to go anywhere. According to Hagrid, elephpotamuses usually get back home moving along their footprints. This is why they never cross them, otherwise they may get lost. When an elephpotamus sees its footprints, it tries to remember in detail all its movements since leaving home (this is also the reason why they move along straight lines only, this way it is easier to memorize). Basing on this information, the animal calculates in which direction its burrow is situated, then turns and goes straight to it. It takes some (rather large) time for an elephpotamus to perform these calculations. And what some ignoramuses recognize as a stupor is in fact a demonstration of outstanding calculating abilities of this wonderful, though a bit slow-witted creature. Elephpotamuses' favorite dainty is elephant pumpkins, and some of such pumpkins grow on the lawn where Harry is to take his exam. At the start of the exam, Hagrid will drag the elephpotamus to one of the pumpkins. Having fed the animal with a pumpkin, Harry can direct it to any of the remaining pumpkins. In order to pass the exam, Harry must lead the elephpotamus so that it eats as many pumpkins as possible before it comes across its footprints. Input The first input line contains the number of pumpkins on the lawn N (3 ≤ N ≤ 30000). The pumpkins are numbered from 1 to N, the number one being assigned to the pumpkin to which the animal is brought at the start of the trial. In the next N lines, the coordinates of the pumpkins are given in the order corresponding to their numbers. All the coordinates are integers in the range from −1000 to 1000. It is guaranteed that there are no two pumpkins at the same location and there is no straight line passing through all the pumpkins. Output In the first line write the maximal number K of pumpkins that can be fed to the elephpotamus. In the next K lines, output the order in which the animal will eat them, giving one number in a line. The first number in this sequence must always be 1.写一段Java完成此目的
最新发布
06-03

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值