team2012-F3-sol-0011
从 Trac 迁移的文章
这是从旧校内 Wiki 迁移的文章,可能存在一些样式问题,您可以向 memset0 反馈。
原文章内容如下:
{{{
题意:给定一条m个折点的折线和n个矩形操作,每个操作是涂色或者擦除颜色,问最后剩余的带色折线段长度是多少。
解法:对于这个折线的每一段进行计算,最后合并起来就是总长度。
将线段与矩形的相交部分用一个区间(l, r)表示,按zYc学长的方法,可以将其全部化到(0, 1)之间。
判断出线段与矩形的相交部分后,将这n个相交部分形成的线段求交,并且进行染色操作
O(n^2)的求交就可以过,就是暴力判断一下相邻两个点在哪个序号最大的线段中。
}}}
{{{
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cmath>
#include <cstring>
#include <utility>
#include <set>
using namespace std;
typedef pair<double, double> PDD;
template<class T> bool takemin(T& a, T b) {bool Z=(a>b); if(Z)a=b; return Z;}
template<class T> bool takemax(T& a, T b) {bool Z=(a<b); if(Z)a=b; return Z;}
const int MAXN = 1003;
int n, m, f[MAXN * 2];
PDD seg[MAXN];
struct r
{
int type;
double x1, x2, y1, y2;
}rec[MAXN];
PDD get_seg(int w, double x1, double y1, double x2, double y2)
{
if(x1 == x2)
{
if(y1 > y2) swap(y1, y2);
if(x1 < rec[w].x1 || x1 > rec[w].x2 || y2 <= rec[w].y1 || y1 >= rec[w].y2) return PDD(0, 0);
double ly = max(y1, rec[w].y1), ry = min(y2, rec[w].y2);
return PDD((ly - y1) / (y2 - y1), (ry - y1) / (y2 - y1));
}
if(y1 == y2)
{
if(x1 > x2) swap(x1, x2);
if(y1 < rec[w].y1 || y1 > rec[w].y2 || x2 <= rec[w].x1 || x1 >= rec[w].x2) return PDD(0, 0);
double lx = max(x1, rec[w].x1), rx = min(x2, rec[w].x2);
return PDD((lx - x1) / (x2 - x1), (rx - x1) / (x2 - x1));
}
if(x1 > x2)
swap(x1, x2), swap(y1, y2);
double lx = max(x1, rec[w].x1), rx = min(x2, rec[w].x2);
if(lx >= rx) return PDD(0, 0);
double dx = x2 - x1, dy = y2 - y1,
k = dy / dx, ly, ry;
if(k > 0)
ly = y1 + (lx - x1) * k, ry = y1 + (rx - x1) * k;
else
ry = y1 + (lx - x1) * k, ly = y1 + (rx - x1) * k;
ly = max(ly, rec[w].y1);
ry = min(ry, rec[w].y2);
if(ly >= ry) return PDD(0, 0);
if(k > 0)
return PDD((ly - y1) / dy, (ry - y1) / dy);
else
return PDD((ry - y1) / dy, (ly - y1) / dy);
}
double dis(double x1, double y1, double x2, double y2)
{
double dx = x1 - x2, dy = y1 - y2;
return sqrt(dx * dx + dy * dy);
}
double gao(double x1, double y1, double x2, double y2)
{
vector<double> pts;
set<double> rep;
for(int i = 1; i <= n; i++)
{
seg[i] = get_seg(i, x1, y1, x2, y2);
if(seg[i].first >= seg[i].second) seg[i] = PDD(0, 0);
if(!rep.count(seg[i].first))
rep.insert(seg[i].first), pts.push_back(seg[i].first);
if(!rep.count(seg[i].second))
rep.insert(seg[i].second), pts.push_back(seg[i].second);
}
sort(pts.begin(), pts.end());
memset(f, 0, sizeof(f));
for(int i = 1; i <= n; i++)
{
double l = seg[i].first, r = seg[i].second,
pre = pts[0], now;
for(int j = 1; j < pts.size(); j++, pre = now)
{
now = pts[j];
if(pre >=l && pre <= r && now >= l && now <= r)
takemax(f[j], i);
}
}
double ret = 0;
for(int i = 1; i < pts.size(); i++)
if(f[i] && rec[f[i]].type)
ret += pts[i] - pts[i-1];
return ret * dis(x1, y1, x2, y2);
}
int main()
{
while(~scanf("%d %d", &n, &m))
{
for(int i = 1; i <= n; i++)
scanf("%d %lf %lf %lf %lf", &rec[i].type, &rec[i].x1, &rec[i].y1, &rec[i].x2, &rec[i].y2);
double x, y, lx, ly, ans = 0;
for(int i = 1; i <= m; i++, lx = x, ly = y)
{
scanf("%lf %lf", &x, &y);
if(i >= 2) ans += gao(lx, ly, x, y);
}
printf("%.2lf\n", ans);
}
return 0;
}
}}}
题意:给定一条m个折点的折线和n个矩形操作,每个操作是涂色或者擦除颜色,问最后剩余的带色折线段长度是多少。
解法:对于这个折线的每一段进行计算,最后合并起来就是总长度。
将线段与矩形的相交部分用一个区间(l, r)表示,按zYc学长的方法,可以将其全部化到(0, 1)之间。
判断出线段与矩形的相交部分后,将这n个相交部分形成的线段求交,并且进行染色操作
O(n^2)的求交就可以过,就是暴力判断一下相邻两个点在哪个序号最大的线段中。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <cmath>
#include <cstring>
#include <utility>
#include <set>
using namespace std;
typedef pair<double, double> PDD;
template<class T> bool takemin(T& a, T b) {bool Z=(a>b); if(Z)a=b; return Z;}
template<class T> bool takemax(T& a, T b) {bool Z=(a<b); if(Z)a=b; return Z;}
const int MAXN = 1003;
int n, m, f[MAXN * 2];
PDD seg[MAXN];
struct r
{
int type;
double x1, x2, y1, y2;
}rec[MAXN];
PDD get_seg(int w, double x1, double y1, double x2, double y2)
{
if(x1 == x2)
{
if(y1 > y2) swap(y1, y2);
if(x1 < rec[w].x1 || x1 > rec[w].x2 || y2 <= rec[w].y1 || y1 >= rec[w].y2) return PDD(0, 0);
double ly = max(y1, rec[w].y1), ry = min(y2, rec[w].y2);
return PDD((ly - y1) / (y2 - y1), (ry - y1) / (y2 - y1));
}
if(y1 == y2)
{
if(x1 > x2) swap(x1, x2);
if(y1 < rec[w].y1 || y1 > rec[w].y2 || x2 <= rec[w].x1 || x1 >= rec[w].x2) return PDD(0, 0);
double lx = max(x1, rec[w].x1), rx = min(x2, rec[w].x2);
return PDD((lx - x1) / (x2 - x1), (rx - x1) / (x2 - x1));
}
if(x1 > x2)
swap(x1, x2), swap(y1, y2);
double lx = max(x1, rec[w].x1), rx = min(x2, rec[w].x2);
if(lx >= rx) return PDD(0, 0);
double dx = x2 - x1, dy = y2 - y1,
k = dy / dx, ly, ry;
if(k > 0)
ly = y1 + (lx - x1) * k, ry = y1 + (rx - x1) * k;
else
ry = y1 + (lx - x1) * k, ly = y1 + (rx - x1) * k;
ly = max(ly, rec[w].y1);
ry = min(ry, rec[w].y2);
if(ly >= ry) return PDD(0, 0);
if(k > 0)
return PDD((ly - y1) / dy, (ry - y1) / dy);
else
return PDD((ry - y1) / dy, (ly - y1) / dy);
}
double dis(double x1, double y1, double x2, double y2)
{
double dx = x1 - x2, dy = y1 - y2;
return sqrt(dx * dx + dy * dy);
}
double gao(double x1, double y1, double x2, double y2)
{
vector<double> pts;
set<double> rep;
for(int i = 1; i <= n; i++)
{
seg[i] = get_seg(i, x1, y1, x2, y2);
if(seg[i].first >= seg[i].second) seg[i] = PDD(0, 0);
if(!rep.count(seg[i].first))
rep.insert(seg[i].first), pts.push_back(seg[i].first);
if(!rep.count(seg[i].second))
rep.insert(seg[i].second), pts.push_back(seg[i].second);
}
sort(pts.begin(), pts.end());
memset(f, 0, sizeof(f));
for(int i = 1; i <= n; i++)
{
double l = seg[i].first, r = seg[i].second,
pre = pts[0], now;
for(int j = 1; j < pts.size(); j++, pre = now)
{
now = pts[j];
if(pre >=l && pre <= r && now >= l && now <= r)
takemax(f[j], i);
}
}
double ret = 0;
for(int i = 1; i < pts.size(); i++)
if(f[i] && rec[f[i]].type)
ret += pts[i] - pts[i-1];
return ret * dis(x1, y1, x2, y2);
}
int main()
{
while(~scanf("%d %d", &n, &m))
{
for(int i = 1; i <= n; i++)
scanf("%d %lf %lf %lf %lf", &rec[i].type, &rec[i].x1, &rec[i].y1, &rec[i].x2, &rec[i].y2);
double x, y, lx, ly, ans = 0;
for(int i = 1; i <= m; i++, lx = x, ly = y)
{
scanf("%lf %lf", &x, &y);
if(i >= 2) ans += gao(lx, ly, x, y);
}
printf("%.2lf\n", ans);
}
return 0;
}