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; }
腾讯公司福利 1143人发布

查看25道真题和解析