605D A. Board Game set+树状数组思想

题目链接: https://codeforces.com/gym/260204/problem/A

题意:

你现在有 n n n 种魔法,每种魔法 i i i 都有四个数值 a [ i ] , b [ i ] , c [ i ] , d [ i ] a[i],b[i],c[i],d[i] a[i],b[i],c[i],d[i] , 现在你有初值 x = 0 , y = 0 x=0,y=0 x=0,y=0 ,一个魔法 i i i 能被使用当且仅当满足 a [ i ] < = x , b [ i ] < = y a[i]<=x,b[i]<=y a[i]<=x,b[i]<=y 时,并且使用完毕后 x = c [ i ] , y = d [ i ] x=c[i],y=d[i] x=c[i],y=d[i] 。现在问你最少要用几个魔法,可以使得魔法 n n n 被使用。

做法:

我们将题目的背景看成一个二维的直角坐标系,将所有的 a [ i ] , b [ i ] a[i],b[i] a[i],b[i] 先画上去,再将 c [ i ] , d [ i ] c[i],d[i] c[i],d[i] 设为这个点的终点。假设我们到了一个点 c [ i ] , d [ i ] c[i],d[i] c[i],d[i] ,那么以这个点为右上角, ( 0 , 0 ) (0,0) (00) 为左下角的矩形中的未被走过的点都能达到了。

在这里插入图片描述

如上图,原来经过的点如果已经被删除的话,就不会到达 O ( n 2 ) O(n^2) O(n2) 的复杂度了。

但是这要怎么存呢(也是在赛上没想出来的原因),先离散化,再用一个树状数组的思想,将点按横坐标向上存,纵坐标不变,每个点携带的信息除了 b [ i ] b[i] b[i] 之外,还有一个编号,查询的时候将所有查过的点清除即可。

可能讲的有点抽象,可以看看代码。

代码

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
typedef pair<int,int> pii;
typedef vector<int> Vi;
const int maxn=100005;
int tmp[maxn<<1],cnt,n,a[maxn],pre[maxn];
int b[maxn],c[maxn],d[maxn],dist[maxn];
set<pii> S[maxn<<1+5];
set<pii>::iterator it,last;
int lowbit(int x){
    return x&(-x);
}
void add(int x,pii p){
    while(x<(maxn<<1)){
        S[x].insert(p);
        x+=lowbit(x);
    }
}
Vi query(int x,int y){
    Vi ret; ret.clear();
    while(x){
        last=S[x].upper_bound({y,maxn});
        for(it=S[x].begin();it!=last;it++){
            ret.push_back(it->second);
        }
        S[x].erase(S[x].begin(),last);
        x-=lowbit(x);
    }
    return ret;
}
void bfs(){
    memset(dist,-1,sizeof(dist));
    memset(pre,-1,sizeof(pre));
    Vi First = query(1,0);
    queue<int> q;
    for(auto x:First) q.push(x),dist[x]=1;
    while(!q.empty()){
        int u=q.front(); q.pop();
        Vi nex=query(c[u],d[u]);
        for(auto v:nex){
            if(dist[v]==-1){
                dist[v]=dist[u]+1;
                pre[v]=u;
                q.push(v);
            }
        }
    }
}
int main(){
    scanf("%d",&n);
    tmp[++cnt]=0;
    rep(i,1,n){
        scanf("%d%d%d%d",&a[i],&b[i],&c[i],&d[i]);
        tmp[++cnt]=a[i],tmp[++cnt]=c[i];
    }
    sort(tmp+1,tmp+1+cnt);
    cnt=unique(tmp+1,tmp+1+cnt)-tmp-1;
    rep(i,1,n){
        a[i]=lower_bound(tmp+1,tmp+1+cnt,a[i])-tmp;
        c[i]=lower_bound(tmp+1,tmp+1+cnt,c[i])-tmp;
        add(a[i],{b[i],i});
    }
    bfs();
    if(dist[n]==-1) printf("-1\n");
    else{
        stack<int> Sa;
        int now=n;
        while(now!=-1){
            Sa.push(now);
            now=pre[now];
        }
        int sz=Sa.size();
        printf("%d\n",sz);
        for(int i=1;i<=sz;i++){
            printf("%d%c",Sa.top(),i==sz?'\n':' ');
            Sa.pop();
        }
    }
    return 0;
}
代码解读void bfs() { while (!q.empty()) { Node cur = q.top(); q.pop(); if (cur.box_x == end_x && cur.box_y == end_y) { best = cur.step; flag = true; break; } else for (int i = 0; i < 4; i++) { flag1 = false; memset(visit2, 0, sizeof(visit2)); int x = cur.box_x + dx[i]; int y = cur.box_y + dy[i]; if (x<1 || y<1 || x>n || y>m || board[x][y] == 1) continue; Node next; next.box_x = x; next.box_y = y; next.people_x = cur.box_x; next.people_y = cur.box_y; next.step = cur.step + 1; if (i == 0) if (cur.box_y - 1 > 0) if (board[cur.box_x][cur.box_y - 1] != 'S' && bfs2(cur.box_x, cur.box_y - 1, cur.box_x, cur.box_y, cur.people_x, cur.people_y) && !visit[x][y][cur.box_x][cur.box_y - 1]) { visit[x][y][cur.box_x][cur.box_y - 1] = 1; q.push(next); } if (i == 1) if (cur.box_y + 1 <= m) if (board[cur.box_x][cur.box_y + 1] != 'S' && bfs2(cur.box_x, cur.box_y + 1, cur.box_x, cur.box_y, cur.people_x, cur.people_y) && !visit[x][y][cur.box_x][cur.box_y + 1]) { visit[x][y][cur.box_x][cur.box_y + 1] = 1; q.push(next); } if (i == 2) if (cur.box_x - 1 > 0) if (board[cur.box_x - 1][cur.box_y] != 'S' && bfs2(cur.box_x - 1, cur.box_y, cur.box_x, cur.box_y, cur.people_x, cur.people_y) && !visit[x][y][cur.box_x - 1][cur.box_y]) { visit[x][y][cur.box_x - 1][cur.box_y] = 1; q.push(next); } if (i == 3) if (cur.box_x + 1 <= n) if (board[cur.box_x + 1][cur.box_y] != 'S' && bfs2(cur.box_x + 1, cur.box_y, cur.box_x, cur.box_y, cur.people_x, cur.people_y) && !visit[x][y][cur.box_x + 1][cur.box_y]) { visit[x][y][cur.box_x + 1][cur.box_y] = 1; q.push(next); } } } }
最新发布
07-14
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值