E. Points, Lines and Ready-made Titles
分类:
disjoint set
math
1.题意概述
- 平面直角坐标系上有 n(1≤n≤105) 个点,你可以在每个点画一条横线或一条竖线或者不划线。问你构成的图像有多少种不同的图?答案取模 109+7 。
2.解题思路
考虑这个画图的特殊性,问题可以转化为:这些点可以产生的横线与竖线的出现情况。
若单独考虑每个点情况显然是 3n 种,但是现在情况就是可能点在同一行或一列,对于这种情况,我们考虑缩点后分情况考虑:对于二维坐标系中的每一行中,对于每个点,如果右边有点,则从该点向右边这个点(相邻的那个点)连一条单向边。对于每一列中,对于每个点,如果该点下面有点,则向下边这个点(相邻的那个点)连一条单向边。然后对于每个点,将与之相连的点并查集合并,合并时如果发现成环,则记这个缩点的集合
tag[i]=1
,否则tag[i]=0
。再算出每个集合中所有点所占据的不重复的行列数,记为dif[i]
。单独考虑缩点后的集合内情况,如图:
3.AC代码
const int maxn = 1e5 + 10;
ll quickmod(ll a, ll b) {
ll ans = 1;
while (b) {
if (b & 1) ans = ans * a % mod;
b >>= 1;
a = a * a % mod;
}
return ans;
}
struct Point {
int x, y, id;
} p[maxn];
inline bool cmp1(const Point& a, const Point& b) {
return a.x < b.x || (a.x == b.x && a.y < b.y);
}
inline bool cmp2(const Point& a, const Point& b) {
return a.y < b.y || (a.y == b.y && a.x < b.x);
}
inline bool cmp3(const Point& a, const Point& b) {
return a.id < b.id;
}
int pa[maxn], dif[maxn];
bool tag[maxn];
int find(int x) {
if (x == pa[x]) return x;
return pa[x] = find(pa[x]);
}
struct Edge {
int to, next;
} E[maxn << 2];
int head[maxn], cnt;
inline void addedge(int u, int v) {
E[cnt].to = v;
E[cnt].next = head[u];
head[u] = cnt++;
}
set<int> x[maxn], y[maxn];
inline void solve() {
int n;
scanf("%d", &n);
cnt = 0;
memset(head, -1,sizeof head);
memset(tag, 0, sizeof tag);
memset(dif, 0, sizeof dif);
rep(i, 1, n + 1) {
pa[i] = p[i].id = i;
scanf("%d%d", &p[i].x, &p[i].y);
}
sort(p + 1, p + n + 1, cmp1);
rep(i, 1, n) {
if (p[i].x == p[i + 1].x) {
addedge(p[i].id, p[i + 1].id);
}
}
sort(p + 1, p + n + 1, cmp2);
rep(i, 1, n) {
if (p[i].y == p[i + 1].y) {
addedge(p[i].id, p[i + 1].id);
}
}
sort(p + 1, p + n + 1, cmp3);
rep(u, 1, n + 1) {
int fu = find(u);
for (int i = head[u]; ~i; i = E[i].next) {
int v = E[i].to;
int fv = find(v);
if (fu == fv) tag[fu] = 1;
else {
pa[fv] = fu;
tag[fu] |= tag[fv];
}
}
}
rep(u, 1, n + 1) {
int fa = find(u);
int sx = p[u].x, sy = p[u].y;
if (x[fa].find(sx) == x[fa].end()) {
dif[fa]++;
x[fa].insert(sx);
}
if (y[fa].find(sy) == y[fa].end()) {
dif[fa]++;
y[fa].insert(sy);
}
}
ll ans = 1;
rep(u, 1, n + 1) {
if (u == find(u)) {
ll res = quickmod(2LL, 1LL * dif[u]);
if (!tag[u]) --res;
ans = ans * res % mod;
}
}
printf("%lld\n", ans);
}