P6405 [COCI2014-2015#2] ŠUMA

BLOG

相邻两棵树的关系是以下几种之一:

  • $h_i=h_j,v_i=v_j$ 永远相等,我们称为 万能边
  • $h_i=h_j,v_i\not = v_j$ 永远不相等。
  • $t=\dfrac{h_i-h_j}{v_j-v_i}$,两棵树当且仅当在时刻 $t$ 时相等。如果时刻 $t<0$ ,那么永远不相等。否则,我们把两棵树的边权设为 $t$。

我们把万能边用并查集缩成一个点,并重新建图。然后把所有的两个数相等的时刻 $t$ 离散化,方便枚举。

枚举时刻 $t$,将所有边权为 $t$ 的两个点合并。并判断最大的连通块。

每个非万能边最多枚举一次。万能边已经缩没了。所以复杂度时 $O(cn^2)$,其中 $c$ 是并查集的复杂度。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define maxn 705
#define put() putchar('\n')
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
using namespace std;
inline void read(int &x){
int f=1;x=0;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
x*=f;
}
namespace Debug{
Tp void _debug(char* f,Ty t){cerr<<f<<'='<<t<<endl;}
Ts void _debug(char* f,Ty x,Ar... y){while(*f!=',') cerr<<*f++;cerr<<'='<<x<<",";_debug(f+1,y...);}
Tp ostream& operator<<(ostream& os,vector<Ty>& V){os<<"[";for(auto& vv:V) os<<vv<<",";os<<"]";return os;}
#define gdb(...) _debug(#__VA_ARGS__,__VA_ARGS__)
}using namespace Debug;
int h[maxn][maxn],v[maxn][maxn],n,m;
int he[maxn*maxn],head=1;
struct yyy{
int to,z,wx,wy;
inline void add(int x,int y,int val,int vall) {
to=y;z=he[x];he[x]=head;wx=val;wy=vall;
}
}a[maxn*maxn*8];
struct edges {
int x,y;
edges(int a=0,int b=0) {x=a;y=b;}
};
int fx[5]={0,1,-1,0,0};
int fy[5]={0,0,0,1,-1};
vector<edges>e[maxn*maxn];
inline int id(int x,int y) {return (x-1)*n+y;}
int size[maxn*maxn],fa[maxn*maxn],vis[maxn*maxn],nsize[maxn*maxn],tr[maxn*maxn];
inline int getfa(int x) {return x==fa[x]?x:fa[x]=getfa(fa[x]);}
inline void merge(int x,int y) {
x=getfa(x),y=getfa(y);
if (x^y) fa[x]=y,size[y]+=size[x];
}
inline void dfs(int x,int cur) {
int i;vis[x]=1,merge(x,cur);
for (i=he[x];i;i=a[i].z) if (a[i].wx==-1&&a[i].wy==-1&&!vis[a[i].to]) dfs(a[i].to,cur);
}
int tot,ans;
ll g[maxn*maxn*4];
const int base=1e6;
signed main(void){
int i,j,k,x,y,gg;
read(n);
for (i=1;i<=n;i++) for (j=1;j<=n;j++) read(h[i][j]);
for (i=1;i<=n;i++) for (j=1;j<=n;j++) read(v[i][j]);
for (i=1;i<=n;i++) {
for (j=1;j<=n;j++) {
for (k=1;k<=4;k++) {
x=i+fx[k],y=j+fy[k];
if (x>=1&&x<=n&&y>=1&&y<=n) ;else continue;
if (v[i][j]==v[x][y]) {
if (h[i][j]==h[x][y]) a[++head].add(id(i,j),id(x,y),-1,-1);
}
else if (h[i][j]==h[x][y]) a[++head].add(id(i,j),id(x,y),0,0);
else {
int tmpy=h[x][y]-h[i][j],tmpx=v[i][j]-v[x][y];
if (1ll*tmpx*tmpy<0) continue;
tmpy=abs(tmpy),tmpx=abs(tmpx);gg=__gcd(tmpx,tmpy);
a[++head].add(id(i,j),id(x,y),tmpy/gg,tmpx/gg);
}
}
}
}
for (i=1;i<=n;i++) for (j=1;j<=n;j++) size[id(i,j)]=1,fa[id(i,j)]=id(i,j);
for (i=1;i<=n;i++) for (j=1;j<=n;j++) if (!vis[id(i,j)]) dfs(id(i,j),id(i,j));//,gdb(i,j,size[getfa(id(i,j))]);
int cnt=0;
for (i=1;i<=n;i++) for (j=1;j<=n;j++) if (fa[id(i,j)]==id(i,j)) tr[id(i,j)]=++cnt,nsize[cnt]=size[id(i,j)];//,gdb(i,j,cnt,nsize[cnt]);
for (i=1;i<=n;i++) {
for (j=1;j<=n;j++) {
int pus=getfa(id(i,j));
for (k=he[pus];k;k=a[k].z) {
int now=getfa(a[k].to);
if (tr[now]!=tr[pus])assert(a[k].wx!=-1),g[++tot]=1ll*a[k].wx*base+a[k].wy;
}
}
}
sort(g+1,g+1+tot);
tot=unique(g+1,g+1+tot)-g-1;
for (i=1;i<=n;i++) {
for (j=1;j<=n;j++) {
int pus=getfa(id(i,j));
for (k=he[pus];k;k=a[k].z) {
int now=getfa(a[k].to);
if (tr[now]!=tr[pus]) {
int w=lower_bound(g+1,g+1+tot,1ll*a[k].wx*base+a[k].wy)-g;
e[w].push_back(edges(tr[pus],tr[now]));
}
}
}
}
for (i=1;i<=cnt;i++) fa[i]=i,size[i]=nsize[i];
for (i=1;i<=tot;i++) {
for (auto tmp:e[i]) {
merge(tmp.x,tmp.y);
ans=max(ans,size[getfa(tmp.x)]);
}
for (auto tmp:e[i]) fa[tmp.x]=tmp.x,size[tmp.x]=nsize[tmp.x],fa[tmp.y]=tmp.y,size[tmp.y]=nsize[tmp.y];
}
printf("%d",ans);
return 0;
}