2016 UESTC Training for Data Structures E - 卿学姐与城堡的墙 树状数组求逆序对、离散化
2016-05-01 00:02
603 查看
E - 卿学姐与城堡的墙
Time Limit: 2000/1000MS (Java/Others) Memory Limit: 65535/65535KB (Java/Others)
Submit
Status
卿学姐终于来到了魔王的城堡,城堡修建的十分壮观。
即使心中放不下公主,卿学姐还是忍不住驻足观赏这宏伟的建筑。
卿学姐注意到城堡的墙上有若干直线状的花纹。
可以将墙看做一个平面,卿学姐想知道有多少种方式任取两个直线,使得这两个直线的交点的横坐标xx满足:u≤x≤vu≤x≤v。
Input
第一行三个整数N,u,v 标明直线有N条。接下来有NN行,每行两个整数k,b
表示这条直线是y=kx+b
1≤N≤200000
0≤|k|≤1000000000
0≤|b|≤1000000000
0≤|u|≤1000000000
0≤|v|≤1000000000
输入保证u≤v ,保证没有两条直线是一样的
Output
输出一个整数,代表选择的方法数。
Sample input and output
Sample Input | Sample Output |
---|---|
3 -3 1 -1 3 2 2 1 1 | 3 |
Hint
上图是样例的解释,交点是A,B,C
Source
2016 UESTC Training for Data Structures Problem E
My Solution
树状数组求逆序数先对uy进行排序,如果a.uy != b.uy 那么uy大的在上面;
如果a.uy == b.uy 那么看vy vy小的在上面, 大的在下面
然后进行1 ~ N的离散化操作,(用树状数组了所以数组不能太大的)
这样就相当于把左边u上的点移到uv内部的,虽然有交点,根据vy大小,有的往上拉,有的往下拉;
然后对对右边vy进行排序,如果a.vy != b.vy 那么uy大的在上面;
如果a.vy == b.vy 那么看uy uy小的在上面, 大的在下面
这样排序相当于把右边v上的交点也移到uv内部去了;
所以已经处理成交点只在uv内部了
然后for i = 1 ~ N
add(seg[i-1].order, 1);
ans += i - get(seg[i-1].order);
扫完就可以输出了☺☺
复杂度 O(nlogn)
另外这里附上一个比较好的讲树状数组求逆序数原理的博客
/article/6009459.html
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <map> #include <queue> using namespace std; const int maxn = 200000 + 8; map<long long,int> s; //用来处理 u == v 的情况 int N; //具体操作的时候要用所以放到全局 struct segment{ long long vy, uy; int order; } seg[maxn]; bool cmpu(const segment& a, const segment& b) { if(a.uy != b.uy) return a.uy > b.uy; else return a.vy < b.vy; } bool cmpv(const segment& a, const segment& b) { if(a.vy != b.vy) return a.vy > b.vy; else return a.uy < b.uy; } //!树状数组求逆序对 int Tree[maxn]; inline int lowbit(int x) { return (x&-x); } void add(int x, int value) { for(int i = x; i <= N; i += lowbit(i)) Tree[i] += value; } int get(int x) { int sum = 0; for(int i = x; i; i -= lowbit(i)) sum += Tree[i]; return sum; } //!!!!!! u, v, k, b; 会在seg[i].uy = k*u + b; seg[i].vy = k*v + b;这中间过程溢出,所以也要 long long 才行了。 //!!!!!! 这里改了然后过来,WA了10次test1,......test就玩溢出,坑坏我了,前天被坑起啊(┬_┬) int main() { #ifdef LOCAL freopen("a.txt", "r", stdin); #endif // LOCAL long long u, v, k, b; //!u <= v ...... u == v long long ans = 0, crosspointsinu = 0; scanf("%d%lld%lld", &N, &u, &v); //!....... u == v 的情况处理错了 for(int i = 0; i < N; i++){ scanf("%lld%lld", &k, &b); seg[i].uy = k*u + b; seg[i].vy = k*v + b; s[seg[i].uy]++; } //据说可以用set去重 sort(seg, seg + N, cmpu); for(int i = 0; i < N; i++){ seg[i].order = i+1; //根据u的值进行离散化 } // if(u == v){ int times; for(auto i = s.begin(); i != s.end(); i++){ times = i->second; if(times != 1){ crosspointsinu += (times*(times-1))/2; } } printf("%lld", crosspointsinu); } else{ sort(seg, seg + N, cmpv); memset(Tree, 0, sizeof Tree); for(int i = 1; i <= N; i++){ add(seg[i-1].order, 1); ans += i - get(seg[i-1].order); } printf("%lld", ans); } return 0; }
Thank you
------from ProLights
相关文章推荐
- 2016 UESTC Training for Data Structures D - 卿学姐与魔法 优先队列、构造
- 2016 UESTC Training for Data Structures C - 卿学姐与诡异村庄 并查集
- 2016 UESTC Training for Data Structures A - 卿学姐与公主 线段树
- 浅谈提高团队成员的工作积极性
- UIView的frame和bounds区别
- 对UITableViewCell的分割线处理
- java中的中断控制 break和continue
- 设置UITableViewCell右侧的箭头
- 8.Binder详解
- IOS之UIScrollView的使用详解
- 自定义UIView重写touchesBegan无法响应点击事件的解决方法
- Leetcode #60. Permutation Sequence 排列组合序列 解题报告
- iOS之UITableViewController使用详解(一)
- UICollectionViewController的使用详解,相册滚动偏移放大
- EasyUI DataGird底部统计行
- UITableView的registerClass forCellReuseIdentifier释义
- ZOJ-3929 Deque and Balls (DP+找规律)
- 关于使用UIPanGestureRecognizer手势touchesBegan不调用的问题
- android-----在子线程中更新UI操作的方法
- Codeforces Round #349 (Div. 2) C. Reberland Linguistics