原本想虐虐蓝桥寻找一下快感,结果随意选了一道题就是二分+扫描线…于是就滚回去补扫秒线了…(我太菜了)
下面以hdu-1542做例子写的一个板子
扫描线的思想很简单放个图应该就不会忘了:
扫描线所构造的线段树叶子结点管辖的是一个区间,为了避免以后脑子犯浑,我还是线段树的构造也写一下吧…
把y坐标离散:
int num = 1;
for (int i = 2; i <= n; i++)
{
if (y[i] == y[i - 1]) continue;
y[++num] = y[i];
}
建树:
void build(int l, int r,int now)
{
tree[now] = node(l, r, 0);
tree[now].len = y[r] - y[l];
tree[now].rl = y[l];
tree[now].rr = y[r];
tree[now].len = 0;
if (r == l + 1)
return;
int mid = (l + r) >> 1;
build(l, mid, now << 1);
build(mid, r, now << 1 | 1);
}
更新:
void pushup(int now)
{
if (tree[now].flag > 0)
{
tree[now].len = tree[now].rr - tree[now].rl;
return ;
}
if (tree[now].l + 1 == tree[now].r) tree[now].len = 0;
else
tree[now].len = tree[now << 1].len + tree[now << 1 | 1].len;
}
void update(double l,double r,int v,int now)
{
if (l <= tree[now].rl && r >= tree[now].rr)
{
tree[now].flag += v;
pushup(now);
return;
}
if (l >= tree[now << 1 | 1].rl)
update(l, r, v, now << 1 | 1);
else if (r <= tree[now << 1].rr)
update(l, r, v, now << 1);
else
{
update(l, r, v, now << 1 | 1);
update(l, r, v, now << 1);
}
pushup(now);
}
getans:
double ans = 0;
for (int i = 1; i < n; i++)
{
update(line[i].y1, line[i].y2, line[i].f, 1);
ans += (line[i + 1].x - line[i].x) * tree[1].len;
}
完整代码:(水一下长度我很开心 >_
#include
#include
#include
#include
#define MAX 100010
using namespace std;
struct node {
double len;
double rl, rr;
int l, r,flag;
node(int _l = 0, int _r = 0,int _flag=0)
{
l = _l; r = _r; flag = _flag;
}
}tree[MAX];//这里不严谨,因为我MAX习惯的开的太大了...所以这里没有乘4/8
struct Line {
double x;
double y1, y2;
int f;
Line(double _x = 0, double _y1 = 0, double _y2 = 0, int _f = 0)
{
x = _x; y1 = _y1; y2 = _y2; f = _f;
}
friend int operator < (Line a,Line b)
{
return a.x < b.x;
}//sort会方便一点,感觉和cmp一样...
}line[300];//开2*n即可
double y[MAX];//同样的2*n
void build(int l, int r,int now)
{
tree[now] = node(l, r, 0);
tree[now].len = y[r] - y[l];
tree[now].rl = y[l];
tree[now].rr = y[r];
tree[now].len = 0;
if (r == l + 1)
return;
int mid = (l + r) >> 1;
build(l, mid, now << 1);
build(mid, r, now << 1 | 1);
}
void pushup(int now)
{
if (tree[now].flag > 0)
{
tree[now].len = tree[now].rr - tree[now].rl;
return ;
}
if (tree[now].l + 1 == tree[now].r) tree[now].len = 0;
else
tree[now].len = tree[now << 1].len + tree[now << 1 | 1].len;
}
void update(double l,double r,int v,int now)
{
if (l <= tree[now].rl && r >= tree[now].rr)
{
tree[now].flag += v;
pushup(now);
return;
}
if (l >= tree[now << 1 | 1].rl)
update(l, r, v, now << 1 | 1);
else if (r <= tree[now << 1].rr)
update(l, r, v, now << 1);
else
{
update(l, r, v, now << 1 | 1);
update(l, r, v, now << 1);
}
pushup(now);
}
void init()
{
memset(tree, 0, sizeof(tree));
memset(y, 0, sizeof(y));
memset(line, 0, sizeof(line));
}
int main()
{
int n;
int len = 1;
while (cin >> n,n)
{
init();
double a, b, c, d;
for (int i = 1; i <= n; i++)
{
cin >> a >> b >> c >> d;
line[i] = Line(a, b, d, 1);
line[n+i] = Line(c, b, d, -1);
y[i] = b; y[i + n] = d;
}
n *= 2;
sort(y + 1, y + n + 1);
int num = 1;
for (int i = 2; i <= n; i++)
{
if (y[i] == y[i - 1]) continue;
y[++num] = y[i];
}
sort(line + 1, line + n + 1);
build(1, num, 1);
double ans = 0;
for (int i = 1; i < n; i++)
{
update(line[i].y1, line[i].y2, line[i].f, 1);
ans += (line[i + 1].x - line[i].x) * tree[1].len;
}
cout << "Test case #" << len++ << endl;
cout << "Total explored area: ";
printf("%.2lf\n\n", ans);
}
return 0;
}