四校联考 推冰块

2<=n,m<=10^9,0<=k<=50000。

我们发现有用的格子不是很多,经过详细的分类讨论,只有这些格子是有用的:

四个角,以及障碍物(或减速带)本身和上下左右四个方向,以及障碍物所在行列(及±1的)的头尾两个。

那么我们只要把所有 障碍 和 减速带 按x-y和y-x排序一下,对于每一个有用的格子二分一下找到往左和往右会推到哪里,连边完暴力bfs即可。

#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>
#include <string>
#include <bitset>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <algorithm>
#include <sstream>
#include <stack>
#include <iomanip>
using namespace std;
#define pb push_back
#define mp make_pair
typedef pair<int,int> pii;
typedef long long ll;
typedef double ld;
typedef vector<int> vi;
#define fi first
#define se second
#define fe first
#define FO(x) {freopen(#x".in","r",stdin);freopen(#x".out","w",stdout);}
#define Edg int M=0,fst[SZ],vb[SZ],nxt[SZ];void ad_de(int a,int b){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;}void adde(int a,int b){ad_de(a,b);ad_de(b,a);}
#define Edgc int M=0,fst[SZ],vb[SZ],nxt[SZ],vc[SZ];void ad_de(int a,int b,int c){++M;nxt[M]=fst[a];fst[a]=M;vb[M]=b;vc[M]=c;}void adde(int a,int b,int c){ad_de(a,b,c);ad_de(b,a,c);}
#define es(x,e) (int e=fst[x];e;e=nxt[e])
#define VIZ {printf("digraph G{\n"); for(int i=1;i<=n;i++) for es(i,e) printf("%d->%d;\n",i,vb[e]); puts("}");}
#ifdef LOCAL
#define TIMER cerr<<clock()<<"ms\n"
#else
#define TIMER
#endif
#define SZ 1234567
int n,m,k,N=0;
int xs[SZ],ys[SZ],ts[SZ];
typedef pair<int,int> pii;
map<pii,int> sta;
bool cmp2(pii a,pii b)
{
    if(a.se!=b.se) return a.se<b.se;
    return a.fi<b.fi;
}
pii ps[SZ]; int pn=0;
pii ss[SZ],rs[SZ];
int dx[4]={1,-1,0,0},dy[4]={0,0,-1,1};
void rec(int a,int b)
{
    if(sta[pii(a,b)]==1) return;
    if(a<1||b<1||a>n||b>m) return;
    ps[++pn]=pii(a,b);
}
int ls(pii a) {return lower_bound(ps+1,ps+1+pn,a)-ps;}
int S,T;
int qs[SZ];
int dist[SZ];
#undef SZ
#define SZ 1234567
Edg
void conn(pii a,pii b)
{
    if(a==b) return;
    ad_de(ls(a),ls(b));
}
void spfa()
{
    int h=0,t=0;
    qs[t++]=S; dist[S]=1;
    while(h^t)
    {
        int x=qs[h++];
        for es(x,e)
        {
            int b=vb[e];
            if(dist[b]) continue;
            dist[b]=dist[x]+1;
            qs[t++]=b;
        }
    }
}
int main()
{
    FO(ice)
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=k;i++)
    {
        scanf("%d%d%d",xs+i,ys+i,ts+i);
        sta[pii(xs[i],ys[i])]=ts[i]+1;
    }
    rec(1,1); rec(n,m);
    rec(1,m); rec(n,1);
    for(int i=1;i<=k;i++)
    {
        rec(xs[i],1); rec(xs[i],m);
        rec(1,ys[i]); rec(n,ys[i]);
        rec(xs[i]+1,1); rec(xs[i]+1,m);
        rec(xs[i]-1,1); rec(xs[i]-1,m);
        rec(1,ys[i]+1); rec(n,ys[i]+1);
        rec(1,ys[i]-1); rec(n,ys[i]-1);
        rec(xs[i],ys[i]);
        for(int j=0;j<4;j++)
        rec(xs[i]+dx[j],ys[i]+dy[j]);
    }
    sort(ps+1,ps+1+pn);
    pn=unique(ps+1,ps+1+pn)-ps-1;
    int sn=0,rn=0;
    for(int i=1;i<=k;i++)
    {
        if(ts[i]==0) ss[++sn]=pii(xs[i],ys[i]);
        else rs[++rn]=pii(xs[i],ys[i]);
    }
    ss[++sn]=pii(-2000000000,-2000000000);
    ss[++sn]=pii(2000000000,2000000000);
    rs[++rn]=pii(-2000000000,-2000000000);
    rs[++rn]=pii(2000000000,2000000000);
    sort(ss+1,ss+1+sn); sort(rs+1,rs+1+rn);
    //先处理左右
    for(int i=1;i<=pn;i++)
    {
        int x=ps[i].fi,y=ps[i].se;
        pii cur=pii(x,y);
        if(y!=1) //L
        {
        int maxn=1;
        int id=lower_bound(rs+1,rs+1+rn,cur)-rs-1;
        pii ns=rs[id];
        if(ns.fi==x) maxn=max(maxn,ns.se);
        id=lower_bound(ss+1,ss+1+sn,cur)-ss-1;
        ns=ss[id];
        if(ns.fi==x) maxn=max(maxn,ns.se+1);
        conn(cur,pii(x,maxn));
        }
        if(y!=m) //R
        {
        int minn=m;
        int id=upper_bound(rs+1,rs+1+rn,cur)-rs;
        pii ns=rs[id];
        if(ns.fi==x) minn=min(minn,ns.se);
        id=upper_bound(ss+1,ss+1+sn,cur)-ss;
        ns=ss[id];
        if(ns.fi==x) minn=min(minn,ns.se-1);
        conn(cur,pii(x,minn));
        }
    }
    sort(ss+1,ss+1+sn,cmp2); sort(rs+1,rs+1+rn,cmp2);
    for(int i=1;i<=pn;i++)
    {
        int x=ps[i].fi,y=ps[i].se;
        pii cur=pii(x,y);
        if(x!=1) //U
        {
        int maxn=1;
        int id=lower_bound(rs+1,rs+1+rn,cur,cmp2)-rs-1;
        pii ns=rs[id];
        if(ns.se==y) maxn=max(maxn,ns.fi);
        id=lower_bound(ss+1,ss+1+sn,cur,cmp2)-ss-1;
        ns=ss[id];
        if(ns.se==y) maxn=max(maxn,ns.fi+1);
        conn(cur,pii(maxn,y));
        }
        if(x!=n) //R
        {
        int minn=n;
        int id=upper_bound(rs+1,rs+1+rn,cur,cmp2)-rs;
        pii ns=rs[id];
        if(ns.se==y) minn=min(minn,ns.fi);
        id=upper_bound(ss+1,ss+1+sn,cur,cmp2)-ss;
        ns=ss[id];
        if(ns.se==y) minn=min(minn,ns.fi-1);
        conn(cur,pii(minn,y));
        }
    }
    S=ls(pii(1,1));T=ls(pii(n,m));
    spfa(); cout<<dist[T]-1<<"\n";
}
时间: 2024-12-19 14:16:37

四校联考 推冰块的相关文章

10.29 FJ四校联考

//四校联考Rank 16 感觉很滋磁 (虽然考的时候抱怨厦门一中出的数学题很NOIP///) 圈地 [问题描述] n根长度不一定相同的木棍,至多可以对其中一根切一刀,然后用其中的任意根围一个三角形,求三角形的最大面积.设面积为S,输出16*S^2对998244353取模后的答案.特别地,无解输出-1. 注:退化的三角形(面积为零)不被认为是三角形,答案应该为-1. [输入文件] 输入文件为tri.in. 输入文件第一行包含两个正整数n和998244353. 第二行包含n个正整数,表示每根木棍的

四校联考2017.8.20T1填算式

由于T2和T3都太高深了太巧妙了,于是只会做T1,拿了95分.现提供95分做法与满分做法 数据范围:n≤13,1≤ai≤9,0≤k≤109 大意:给n个数,在其中填+?×,允许多个数合并为一个.求使得最终结果等于k的算式数量.(这不就是我们平常玩的24点的加强版吗?) 95分解法:我们注意到对于第一个数字,其前面的操作只能为加法,对于之后的每一个数字,我们都有四种操作:在前面填加号,减号,乘号:与前面的数字合并.注意到n的值很小,于是考虑深搜.用两个数组分别记这个算式的符号和数字,当深搜到最后的

2017-2-26福建四校联考

哎我好菜啊 从来没打过表的萌新这次想打个表结果打太多了长度超限了(后来发现根本没必要打表) ---------我是分割线 A.矩形 给定一个2*n的矩形,每个位置有一个正权值,你要把它恰好分成m个矩形,使得所有矩形的和的最大值最小并求出最小的最大值. n<=100000 m<=100 题解: 首先很显然m只是一个附加条件,如果你能分<m段,那么你一定能分m段. 看到最大值最小,最小值最大的问题,很自然想到二分答案. 然后我们用一个dp来check.用f[i]表示前i*2的矩形至少要分几段

2016年9月25日四校联考

·前言:啊f**k今天早上体检,但是并不影响做题2333因为题目真的好 NOIP 啊 啊对了附中评测姬好坑啊正解强行T 23333 第一题<萝卜种子> 简要题意:小姑娘看了看狐狸的萝卜田,发现田里最多只能生长7个萝卜(多余的种子不会发芽),且4种萝卜发芽的概率是完全相同的.它们的效果分别是: 普通萝卜:生产2kg兔粮 超能萝卜:生产2kg兔粮,每种植一个其他萝卜额外产生1kg兔粮 固氮萝卜:不能用于生产兔粮,但能使每个普通萝卜和超能萝卜生产的兔粮+1kg 金坷垃萝卜:不能用于生产兔粮,但能使每

2017-3-5四校联考

szy学长出的,除了T3外都比较水 360/400. T1.小猪划船 题目大意:六只猪要过河,三只大猪ABC,三只小猪abc,其中ABCa会划船,共一只船,每次可以载2个人,给出四只猪的划船耗时,每次运载花的时间是船上耗时最小的猪的耗时乘上船上猪的个数,小猪与其对应大猪不在一起时不能与其他大猪在一起,求所有猪到对岸的最小耗时. 思路:状态最多2^7(每只猪还有船的位置),随便建图最短路或者直接搜索或者构造都能通过该题.我写的O(2^21). #include<cstdio> #include&

2017-4-9四校联考

T2结论推得有点问题结果只有30,T3暴力骗了40,170/300 T1.交易 题目大意:一个人从0走到m,走1要1s,路上有n个点xi,每个点必须被经过2次,第二次要在第一次的ts之后经过才算数,求最少时间.(n<=3,000,000,0<xi<m<=10^9) 思路:f[i]表示完成前i个点后到达第i个点的最小时间,每次回头显然必须完成所有之前未完成的点,故有f[i]=min(f[j]+x[i]-x[j]+max(2*(x[i]-x[j+1]),t)),把max分开讨论,当2*

20170814四校联考

啊啊啊啊啊啊NOIAu大神ysy出题虐菜出人命啦!爆tan(pi/4)啦!被害者家属情绪稳定. ysy大佬谁敢D啊,NOIAu1st了,只适合D人了. 还是IOIAu的大佬体谅人,我还那么蒟蒻呢~ 闲话不说,上题目: T1: 宝石(gem) [题目描述]有 n 座城市,编号为 1~n,第 i 座城市里宝石的交易价格为 ai.当你经过第 i 座城市时,你可以以 ai 的价格购买或卖出一个宝石.在任意时刻,你最多只能携带一个宝石.有 m 次操作,操作分为两种:(1) 给定l,r,询问依次经过编号为l

20170820四校联考

来看看IOIAu巨神zzx的名言 不用循环输入就会狗啊哥哥! 上题目: T1: 填算式(expr) [题目描述] 填算式是一种简单的数学游戏,可以形式化描述如下:n 个数字a1; a2; -- ; an 排成一排(1<= ai<=9),相邻两个数字之间有一个空格.你可以在每个空格内填入运算符+- * 之一,也可以不填,要求得到的算式的运算结果等于k.你的任务是计算有多少种不同的正确算式.比如n = 3,3 个数字为2; 2; 2,k = 24时,有两种不同的正确算式:22 + 2 = 24,2

四校联考——20170730模拟赛

今天3题都很丧. 我只会T1,所以我很弱 T1要有桶排序,不然会T,被卡常 做法就是先排序,然后前缀和乱搞 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define ll long long #pragma o1 using namespace std; inline int read(){ int x=0;char c=getchar();bool t