J 能到达吗 题解

能到达吗

http://www.nowcoder.com/questionTerminal/b6978a0a6f3445a48482e7151f58e2cc


你有一个 的矩阵 定义两个格子联通为四联通

求出所有联通块的 其中 为联通块大小


考虑扫描线

首先找出所有的整个的矩形然后相邻行的合并即可

合并可以用并查集实现

细节比较多不太好写

复杂度

#include <bits/stdc++.h>
#define LL long long
#define int long long
using namespace std;
template <typename T> void read(T &x){
    x = 0; char ch = getchar();
    while (!isdigit(ch)) ch = getchar();
    while (isdigit(ch)) x = x * 10 + ch - '0',ch = getchar();
}
const int K = 2000050,N = 200050,P = 1e9 + 7;
int n,m,k;
struct Point{ int x,y; Point(int xx=0,int yy=0){ x=xx,y=yy; } }a[K];
vector<int>G[N];
inline bool cmpxp(Point A,Point B){ return (A.x != B.x) ? (A.x < B.x) : (A.y < B.y); }
int fa[K<<1],size[K<<1];
inline int Find(int x){ return x == fa[x] ? x : fa[x] = Find(fa[x]); }
inline void Merge(int x,int y){ if ((x=Find(x))==(y=Find(y))) return; fa[y] = x,size[x] = (size[x]+size[y])%P; }

struct Mat{ int xl,xr,yl,yr; }ma[K<<1]; int cntid;
inline bool cmpx(Mat A,Mat B){ return (A.xl != B.xl) ? (A.xl < B.xl) : (A.yl < B.yl); }
int vx[K],lv; int vis[N];

int lb,b[N],bl[N],br[N],fl[N],fr[N];
int lc,c[N],cl[N],cr[N];
inline bool check(int l1,int r1,int l2,int r2){ return max(l1,l2) <= min(r1,r2); }
inline void work(int l1,int r1,int l2,int r2){
    int i,j,cll,crr,L,R,Mid;
    lb = r1-l1+1; for (i = l1; i <= r1; ++i) b[i-l1+1] = i;
    lc = r2-l2+1; for (i = l2; i <= r2; ++i) c[i-l2+1] = i;
    for (i = 1; i <= lb; ++i) bl[i] = ma[b[i]].yl,br[i] = ma[b[i]].yr,fl[i] = -1,fr[i] = -2;
    for (i = 1; i <= lc; ++i) cl[i] = ma[c[i]].yl,cr[i] = ma[c[i]].yr;
    for (i = 1; i <= lb; ++i) if (check(bl[i],br[i],cl[1],cr[lc])){
        fl[i] = 1,L = 1,R = lc;
        while (L <= R){
            Mid = L+R>>1; if (cr[Mid] < bl[i]) fl[i] = Mid + 1,L = Mid + 1; else R = Mid - 1;
        }
        L = fl[i],R = lc,fr[i] = fl[i]-1;
        while (L <= R){
            Mid = L+R>>1; if (cl[Mid] <= br[i]) fr[i] = Mid,L = Mid + 1; else R = Mid - 1;
        }
        if (!check(fl[i],fr[i],1,lc)) bl[i] = -1,br[i] = -2;
        else if (!check(bl[i],br[i],cl[fl[i]],cr[fl[i]])) bl[i] = -1,br[i] = -2;
        else if (!check(bl[i],br[i],cl[fr[i]],cr[fr[i]])) bl[i] = -1,br[i] = -2;
        else Merge(b[i],c[fl[i]]);
    }
    int lst = -1,nl = -1,nr = -2;
    for (i = 1; i <= lb; ++i) if (fl[i] <= fr[i]){
        if (lst != -1 && check(nl,nr,fl[i],fr[i])) Merge(lst,b[i]),nr = fr[i];
        else{
            if (lst != -1) for (j = nl; j <= nr; ++j) Merge(lst,c[j]);
            lst = b[i],nl = fl[i],nr = fr[i];
        }
    }
    if (lst != -1) for (i = nl; i <= nr; ++i) Merge(lst,c[i]);
}
inline void solve(){
    int i,j,v,t;
    read(n),read(m),read(k),cntid = 0;
    for (i = 1; i <= k; ++i) read(a[i].x),read(a[i].y);
    sort(a+1,a+k+1,cmpxp);
    vx[lv=1]=0;
    for (i = 1; i <= k; ++i) G[a[i].x].push_back(a[i].y),vx[++lv] = a[i].x,vis[a[i].x] = 0;
    vx[++lv] = n+1;
    sort(vx+1,vx+lv+1);
    cntid = 0;
    for (i = 1; i < lv; ++i) if (vx[i] + 1 < vx[i+1]){
        ++cntid;
        ma[cntid].yl = 1,ma[cntid].yr = m;
        ma[cntid].xl = vx[i]+1,ma[cntid].xr = vx[i+1]-1;
    }
    for (i = 1; i <= k; ++i) if (!vis[a[i].x]){
        t = a[i].x; vis[t] = 1;
        G[t].push_back(0),G[t].push_back(m+1); sort(G[t].begin(),G[t].end());
        for (j = 0; j < G[t].size()-1; ++j) if (G[t][j] + 1 < G[t][j+1]){
            ++cntid;
            ma[cntid].yl = G[t][j]+1,ma[cntid].yr = G[t][j+1]-1;
            ma[cntid].xl = ma[cntid].xr = t;
        }
        G[t].clear();
    }
    sort(ma+1,ma+cntid+1,cmpx);
    for (i = 1; i <= cntid; ++i)
        fa[i] = i,size[i] = 1ll * (ma[i].xr-ma[i].xl+1) * (ma[i].yr-ma[i].yl+1) % P;
    int nl = 1,nr = 1,nxl = ma[1].xl,ll = -1,lr = -1;
    for (i = 2; i <= cntid; ++i){
        if (nxl == ma[i].xl){ nr = i; continue; }
        if (ll != -1 && abs(ma[ll].xr-ma[nl].xl) == 1) work(ll,lr,nl,nr);
        ll = nl,lr = nr; nl = nr = i,nxl = ma[i].xl;
    }
    if (ll != -1 && abs(ma[ll].xr-ma[nl].xl) == 1) work(ll,lr,nl,nr);
    for (i = 1; i <= k; ++i) G[a[i].x].clear(),vis[a[i].x] = 0;
    int ans = 0;
    for (i = 1; i <= cntid; ++i) if (fa[i] == i) ans = (ans + 1ll * size[i] * (size[i]+1)/2 % P) % P;
    cout << (ans+P)%P << '\n';
}

signed main(){ int T; read(T); while (T--) solve(); return 0; }
全部评论

相关推荐

2025-12-25 10:16
已编辑
合肥工业大学 后端工程师
如题,在历经了长达多月的焦急等待,楼主也算是如愿以偿收到了梦中情司的意向了,秋招也终于是落下了帷幕,虽然手中的offer不够打牌,但已经满足了。华为时间线:9.3&nbsp;笔试环节,惊险通过10.15&nbsp;线下面试,前两轮技术面手撕都比较轻松,面试官态度也很好,最后一轮主管面,向主管表达了强烈的意愿,主管很和蔼,面试体验非常棒,1125定律后入池成功11.19&nbsp;收到接口人的保温电话12.9&nbsp;接到部门hr的保温电话,介绍了一下部门负责的工作12.23&nbsp;收到华为的意向书,成为华孝子一枚~期间收到了之前实习过的公司的offer,害怕华子泡不出来就先签三方了,这下不得不毁约了,在此向前司道个歉,也感谢前司对我的认可和托举,祝业务蒸蒸日上~感谢从今年三月开始找暑期实习以来,所有朋友和家人的鼓励,我们宿舍的就业氛围相当好,大家会分享各种有用的信息以及面试中遇到刁钻的面试题,在有人收到offer的时候我们都会发自内心的高兴和祝福,在我去线下面的时候也借我穿过西服.....能在大学四年分入这么好的宿舍拥有这么这么好的舍友除了幸运我找不出其他的形容词。还要感谢我的父母,在我每一次面试前都给予鼓励,也在失败的时候安慰我,他们的托底是我前进的基石,以后有工资了要给父母买很多东西最感谢的是我的女朋友,我们从大一相识,一直坚持到大四,她是一个非常优秀也异常坚定的女生,也正是因为她的实力出众早再年初就定好了要去上海的一家外企。我为了也去上海,从暑期实习开始投了不少上海的岗位但无一例外的都被拒之门外,但这期间她从来没有嫌弃过我,反而一直鼓励我相信我,如果说父母的托底是我前进的基石,那女朋友的鼓励和信任则是我前进的动力和方向。在如今这个充满戾气和对立的社会,能找到一个一心一意彼此喜欢的人实在是很难得,我深知这种珍贵所以更会加倍珍惜也感谢自己吧,在经历了无数个失眠的夜晚和面试失败的打击下,最终还是迎来了最好的结果,记得在华为线下面的前几周我几乎回到了高三时期的作息,那真是一段充实美好的时光,好在最后的结果也没有辜负这份努力也想跟所有的牛友说:不要因为一时的失败而自怨自艾,妄自菲薄,只要坚持下去,总会有柳暗花明又一村的惊喜在等待着你,机会总是垂青于有准备的人,要相信否极泰来,相信自己。朋友,坚定地相信未来吧,相信不屈不挠的努力,相信战胜死亡的年轻,相信未来、热爱生命。
小肥罗:有这样的女朋友真是幸福
秋招白月光
点赞 评论 收藏
分享
评论
1
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务