Codeforces 223E. Planar Graph(平面图)
http://codeforces.com/problemset/problem/223/E
题解:
本题做法:
因为是个连通图,可以神奇的转换:
1.有一汇点T,每个点有一个流量朝汇点流,可以发现每个点的出流-入流=1(自己多的1)
2.从汇点T开始dfs,随便保留一个生成树作为流量树,发现一条边流量等于子树点数
3.对于一个环,它的内部点数=出去外面的流量-从外面来的流量
4.对环上每个点,把出边按几角排好序,预处理前缀和,在上面二分即可得到答案。
更加通用的做法:
1.平面图转对偶图
2.平面图欧拉公式:V+F=E+2
2.一个平面图环内的点数,=对偶图上删掉对应的边,环围成的点所在联通块的边数+2-点数。
3.相当于每条边有一个存在时间,查询一个时间一个点的联通块的边数和点数,经典分治+可撤销并查集即可解决。
Code:
#include<bits/stdc++.h>
#define fo(i, x, y) for(int i = x, B = y; i <= B; i ++)
#define ff(i, x, y) for(int i = x, B = y; i < B; i ++)
#define fd(i, x, y) for(int i = x, B = y; i >= B; i --)
#define ll long long
#define pp printf
#define hh pp("\n")
using namespace std;
const int N = 3e5 + 5;
#define db double
int n, m, x, y;
vector<int> e[N];
#define pb push_back
#define si size()
struct P {
db x, y;
P(db _x = 0, db _y = 0) {
x = _x, y = _y;
}
} a[N];
P operator + (P a, P b) { return P(a.x + b.x, a.y + b.y);}
P operator - (P a, P b) { return P(a.x - b.x, a.y - b.y);}
db operator ^ (P a, P b) { return a.x * b.y - a.y * b.x;}
db operator * (P a, P b) { return a.x * b.x + a.y * b.y;}
P operator * (P a, db b) { return P(a.x * b, a.y * b);}
int fa[N], bz[N], siz[N];
db ang(P a, P b) {
return atan2(b.y - a.y, b.x - a.x);
}
vector<P> s[N];
int cmpe(P a, P b) {
return a.x < b.x;
}
int d[N], d0;
void dg(int x) {
d[d0 = 1] = x; bz[x] = 1;
for(int i = 1; i <= d0; i ++) {
int x = d[i];
ff(_y, 0, e[x].si) {
int y = e[x][_y];
if(bz[y]) continue;
fa[y] = x;
bz[y] = 1;
d[++ d0] = y;
}
}
fd(i, d0, 1) {
int x = d[i];
siz[x] = 1;
ff(_y, 0, e[x].si) {
int y = e[x][_y];
if(fa[y] != x) continue;
siz[x] += siz[y];
s[x].pb(P(ang(a[x], a[y]), -siz[y]));
}
if(fa[x] <= n) {
s[x].pb(P(ang(a[x], a[fa[x]]), siz[x]));
}
if(s[x].si) {
sort(s[x].begin(), s[x].end(), cmpe);
ff(j, 1, s[x].si) s[x][j].y += s[x][j - 1].y;
}
}
}
void build() {
int t = 1;
fo(i, 2, n) if(a[i].x < a[t].x) t = i;
e[n + 1].pb(t); e[t].pb(n + 1);
dg(n + 1);
}
int Q, k;
P b[N]; int c[N];
void check_order() {
db s = 0;
fo(i, 2, k - 1) s += (b[i] - b[1]) ^ (b[i + 1] - b[1]);
if(s < 0) {
reverse(b + 1, b + k + 1);
reverse(c + 1, c + k + 1);
}
}
const db pi = acos(-1);
const db eps = 1e-11;
ll ef(vector<P> &s, db p) {
int as = -1;
for(int l = 0, r = s.si - 1; l <= r; ) {
int m = l + r >> 1;
if(s[m].x <= p) as = m, l = m + 1; else r = m - 1;
}
if(as == -1) return 0;
return s[as].y;
}
ll solve(int x, db p, db q) {
ll ans = 0;
if(fa[x] > n) ans += siz[x];
if(s[x].si == 0) return ans;
if(p <= q) ans += ef(s[x], p - eps) + (s[x][s[x].si - 1].y - ef(s[x], q + eps)); else
ans += ef(s[x], p - eps) - ef(s[x], q + eps);
return ans;
}
int main() {
freopen("graph.in", "r", stdin);
freopen("graph.out", "w", stdout);
scanf("%d %d", &n, &m);
fo(i, 1, m) {
scanf("%d %d", &x, &y);
e[x].pb(y); e[y].pb(x);
}
fo(i, 1, n) scanf("%lf %lf", &a[i].x, &a[i].y);
build();
scanf("%d", &Q);
fo(ii, 1, Q) {
scanf("%d", &k);
fo(i, 1, k) {
scanf("%d", &c[i]);
b[i] = a[c[i]];
}
check_order();
ll ans = 0;
fo(i, 1, k) {
ans += solve(c[i], ang(b[i], i == k ? b[1] : b[i + 1]), ang(b[i], i == 1 ? b[k] : b[i - 1]));
}
pp("%lld\n", ans);
}
}
转载注意标注出处:
转自Cold_Chair的博客+原博客地址