ZOJ--3574--Under Attack II【线段树+欧拉公式】
来源:互联网 发布:手机淘宝掌柜热卖在哪 编辑:程序博客网 时间:2024/05/19 02:19
链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3574
题意:一个坐标系,给出x1、x2限定左右边界,有n条直线,告诉每条直线的k和b,问在x1、x2区间内空间被直线分割成几部分
思路:
这道题是比赛时做的,AC之后发现别人都是用归并排序求逆序对数来解的。
说我的解法吧,首先拿到题的时候发现是划分区域这样的,第一下就想到了欧拉公式,但是n有30000,n^2找交点肯定要超时。土豪在纸上画了一下,一条直线必然在x1和x2处留下两点,如果一个直线左端点在另一个直线左端点上面,右端点在另一条线右端点下面,则他们必有一个交点。于是可以转换成线段树来做,给左端点从小到大排序,查询比当前直线右端点大的点的数目,更新欧拉公式要用到的点数和边数,注意交点在x1、x2时的情况。由于欧拉公式适用于连通图,所以要借助x1、x2两条边界线,但是直线没有端点,再虚拟出上下两个边界构出顶点,这样必定是连通图,所以初始时点数和边数都是4。
由于题目说了不会有三条线交于一点的情况,所以处理起来方便很多。
细节:
1.k*x1+b之后的数可能会很大,但是直线最多只有30000条,所以离散化处理。
2.我两个地方写逗了卡了较长时间。写下来防止以后犯逗:
(1)建树顺手写在了输入直线数之后,简单的样例发现不了,因为直线右端点如果没重合的话是不会有影响的。应当写在离散化之后。范围就到离散化后最大的数。
(2)调用query2函数是L、R的取值问题,我为了图省事R直接取到xx+1,如果前一组样例离散化后值较大,后一组较小,则xx+1就会取到上一组的情况,导致答案出错,我尝试建树时范围更大些,但是结果还是WA。解决方案是不要图省事,就取到xx。或者每组样例memset一下sum数组,但是这样显然很慢。
#include<cstring>#include<string>#include<sstream>#include<fstream>#include<iostream>#include<iomanip>#include<cstdio>#include<cctype>#include<algorithm>#include<queue>#include<deque>#include<map>#include<set>#include<vector>#include<stack>#include<ctime>#include<cstdlib>#include<functional>#include<cmath>using namespace std;#define PI acos(-1.0)#define MAXN 30010#define eps 1e-7#define INF 0x3F3F3F3F //0x7FFFFFFF#define LLINF 0x7FFFFFFFFFFFFFFF#define seed 1313131#define MOD 1000000007#define ll long long#define ull unsigned ll#define lson l,m,rt<<1#define rson m+1,r,rt<<1|1struct node{ int y1, y2;}line[MAXN];int sum[MAXN << 2];int n;map<int, int> mp;bool cmp(node x, node y){ return x.y1 < y.y1;}bool operator == (node p1, node p2){ return p1.y1 == p2.y1 && p1.y2 == p2.y2;}void pushup(int rt){ sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];}void build(int l, int r, int rt){ sum[rt] = 0; if(l == r) return ; int m = (l + r) >> 1; build(lson); build(rson);}void update(int pos, int l, int r, int rt){ if(l == r){ sum[rt]++; return ; } int m = (l + r) >> 1; if(pos <= m) update(pos, lson); else update(pos, rson); pushup(rt);}int query1(int pos, int l, int r, int rt){ if(l == r){ return sum[rt]; } int m = (l + r) >> 1; if(pos <= m) query1(pos, lson); else query1(pos, rson);}int query2(int L, int R, int l, int r, int rt){ if(L <= l && r <= R){ return sum[rt]; } int m = (l + r) >> 1; int res = 0; if(L <= m) res += query2(L, R, lson); if(R > m) res += query2(L, R, rson); return res;}int aaa[MAXN];int fuck[MAXN];int main(){ int x1, x2; int i, j, k, b; ll ppp, lll; while(scanf("%d%d", &x1, &x2) != EOF){ mp.clear(); ppp = 4; lll = 4; scanf("%d", &n); int m = 0; int flag = 0; for(i = 0; i < n; i++){ scanf("%d%d", &k, &b); line[m].y1 = k * x1 + b; line[m].y2 = k * x2 + b; if(line[m].y1 != line[m].y2) flag = 1; aaa[m] = line[m].y2; m++; } sort(aaa, aaa + m); int xx = unique(aaa, aaa + m) - aaa; if(x1 == x2 && flag == 0){ printf("%d\n", xx + 1); continue; } for(i = 0; i < xx; i++){ mp[aaa[i]] = i + 1; } build(1, xx + 1, 1); sort(line, line + m, cmp); m = unique(line, line + m) - line;// cout<<m<<endl; ll ans = 0; for(i = 0; i < m; i++){ j = i; while(line[i + 1].y1 == line[i].y1 && i + 1 < m) i++; ppp++; lll += i - j + 1; lll++; for(int ii = j; ii <= i; ii++){ int ttt = mp[line[ii].y2]; int temp = query1(ttt, 1, n, 1); if(!temp){ lll++; ppp++; } if(ttt + 1 <= xx){ temp = query2(ttt + 1, xx, 1, n, 1); ppp += temp; lll += temp * 2; } } for(int ii = j; ii <= i; ii++){ update(mp[line[ii].y2], 1, n, 1); } }// cout<<ppp<<" "<<lll<<endl; ans = 2 - ppp + lll - 1; printf("%lld\n", ans); } return 0;}
- ZOJ--3574--Under Attack II【线段树+欧拉公式】
- zoj 3574 Under Attack II//归并排序
- 【归并排序】ZOJ-3574-Under Attack II
- ZOJ 3573 Under Attack (线段树版)
- ZOJ3574 Under Attack II【线段树】
- zoj Monthly, February 2012 - D Under Attack II (zoj 3574)
- ZOJ 3574 Under Attack II 归并排序求逆序对
- ZOJ 3574 Under Attack II 归并排序求逆序对
- ZOJ 3573 Under Attack (线段树两边维护最大值)
- zoj3573 Under Attack (线段树)
- zoj 3573 Under Attack
- zoj 3573 Under Attack
- zoj 3573 Under Attack
- zoj 3573 Under Attack
- ZOJ 3573 Under Attack
- zoj 3573 Under Attack(线段树 标记法 最大覆盖数)
- Under Attack II
- ZOJ 3575 Under Attack III
- LeetCode: Single Number II
- android--监听按键
- Intent常用系统调用
- Leetcode Count and Say
- 机器学习基础知识-回归与梯度下降法
- ZOJ--3574--Under Attack II【线段树+欧拉公式】
- 手动创建数据库脚本以及报错处理:ORA-01519ORA-00604ORA-30012
- 会场安排问题(南阳oj14)(贪心-区间不重叠)
- WEBERP测试实录:一 webERP安装
- C++ STL map类型简介
- android之Android.mk小结
- Opencv step by step - 自适应阈值
- android:background="#eee"是什么?
- SELECT INTO 和 INSERT INTO SELECT 两种表复制语句