poj 3067 Japan
来源:互联网 发布:linux系统函数api手册 编辑:程序博客网 时间:2024/05/05 05:28
点击打开链接poj 3067
思路:线段树
分析:
1 题目要求的是找到所有直线的交点总数,并且题目明确指出两条直线之间最多只有一个交点
2 很明显我们应该先对这些直线进行排序:按照左边的编号从小到大,左边编号相同时按照右边编号从小到大。那么假设现在有一条直线1-3,那么能够和这条直线有交点的肯定是右边的编号大于3的,那么这个过程就可以利用线段树的查找,查找完毕还要更新线段树。
3 由于题目的n最大5*10^5,那么最坏的情况1+2+...n,会超过int , 所以我们应该选择long long.
代码:
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define MAXN 1000010int n , m , k;struct Point{ int x; int y;};Point p[MAXN];struct Node{ int left; int right; int sum;};Node node[4*MAXN];bool cmp(Point a , Point b){ if(a.x < b.x) return true; else if(a.x == b.x && a.y < b.y) return true; return false;}void buildTree(int left , int right , int pos){ node[pos].left = left; node[pos].right = right; node[pos].sum = 0; if(left == right) return; int mid = (left+right)>>1; buildTree(left , mid , pos<<1); buildTree(mid+1 , right , (pos<<1)+1);}int query(int left , int right , int pos){ if(node[pos].left == left && node[pos].right == right) return node[pos].sum; int mid = (node[pos].left + node[pos].right)>>1; if(right <= mid) return query(left , right , pos<<1); else if(left > mid) return query(left , right , (pos<<1)+1); else return query(left , mid , pos<<1)+query(mid+1 , right , (pos<<1)+1);}void update(int index , int pos){ if(node[pos].left == node[pos].right){ node[pos].sum++; return; } int mid = (node[pos].left+node[pos].right)>>1; if(index <= mid) update(index , pos<<1); else update(index , (pos<<1)+1); node[pos].sum = node[pos<<1].sum + node[(pos<<1)+1].sum;}int main(){ int t , Case = 1; long long ans;//选择long long scanf("%d" , &t); while(t--){ scanf("%d%d%d" , &n , &m , &k); for(int i = 0 ; i < k ; i++) scanf("%d%d" , &p[i].x , &p[i].y); sort(p , p+k , cmp); buildTree(1 , m , 1); ans = 0; for(int i = 0 ; i < k ; i++){ if(p[i].y < m) ans += query(p[i].y+1 , m , 1); update(p[i].y , 1); } printf("Test case %d: %lld\n" , Case++ , ans); } return 0;}
思路:树状数组
分析:
1 题目要求的是找到所有直线的交点总数,并且题目明确指出两条直线之间最多只有一个交点At most two superhighways cross at one location
2 我们应该先对这些直线进行排序:按照左边的编号从小到大,左边编号相同时按照右边编号从小到大。那么假设现在有一条直线1-3,那么能够和这条直线有交点的肯定是右边的编号大于3的,那么这个过程就可以利树状数组求和得到,求和完毕还要更新树状数组。
3 由于题目的k没有给定,那么最坏的情况1+2+...k
4 数据会超过int , 所以我们应该选择long long
代码;
#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;const int N = 1010;const int MAXN = 1000010;struct Node{ int x; int y; bool operator<(const Node& s)const{ if(x < s.x) return true; else if(x == s.x && y < s.y) return true; return false; }};Node node[MAXN];int n , m , k;long long treeNum[N];int lowbit(int x){ return x&(-x);}long long getSum(int x){ long long sum = 0; while(x){ sum += treeNum[x]; x -= lowbit(x); } return sum;}void add(int x , int val){ while(x < N){ treeNum[x] += val; x += lowbit(x); }}long long solve(){ long long ans = 0; memset(treeNum , 0 , sizeof(treeNum)); sort(node , node+k); for(int i = 0 ; i < k ; i++){ ans += i-getSum(node[i].y); add(node[i].y , 1); } return ans;}int main(){ int cas = 1; int Case; scanf("%d" , &Case); while(Case--){ scanf("%d%d%d" , &n , &m , &k); for(int i = 0 ; i < k ; i++) scanf("%d%d" , &node[i].x , &node[i].y); printf("Test case %d: %lld\n" , cas++ , solve()); } return 0;}
- POJ 3067 Japan
- poj 3067 Japan
- POJ 3067 - Japan
- poj 3067 Japan
- Poj 3067 Japan
- poj 3067 Japan
- POJ 3067 Japan
- Poj 3067 Japan
- POJ 3067 Japan
- POJ 3067 Japan
- POJ-3067-Japan
- POJ 3067 Japan
- POJ 3067 Japan
- poj 3067 Japan
- POJ 3067 Japan
- POJ 3067 Japan
- poj 3067 Japan
- POJ 3067 Japan
- Qt多线程学习:创建多线程
- OGRE分析之设计模式(二)
- Flume-ng生产环境实践(三)实现文件sink,按照固定格式目录输出
- Vim中的swp文件
- Flex 4.0解决Session问题的山寨版方法
- poj 3067 Japan
- as3 中的数学函数atan与atan2
- android学习---- WindowManager.LayoutParams
- RGB颜色空间
- 基本算术运算符01
- HttpServletRequest对象方法的用法
- spring依赖注入,运行报空指针异常
- PowerDesigner中从注释生成Name的两个升级VBS脚本
- OGRE分析之设计模式(三)