Time Limit: 15000MS | Memory Limit: 65536K | |
Total Submissions: 3237 | Accepted: 664 | |
Case Time Limit: 3000MS |
Description
Input
Output
Sample Input
4 0 2 2 1 3 8 6 3
Sample Output
2 3 4 1 2
题意:飞船往同一方向飞,已知每个飞船的起点(不重合)和速度,问题一:每个飞船被超过的次数的总和(模1000000);问题二:输出前10000次超越,按照时间排序,若时间相同按照超越别飞船的飞船的输入顺序排序。
解题思路:
问题一:按照起点排序(输入已经给我们排好),若前一个速度比当前的速度大,则前面那个飞船一定能超越当前飞船,否则不可能。因此,只要算一下逆序数和就可以了。
问题二:第一个超越的一定是相邻两个飞船。
反证:设当前位置为A-B-C,若第一次超越为A->C,则必定A->B或B->C,与A->C为第一次超越矛盾。
因此:
这样,我就能保证每次输入的就是当前最早超越的飞船!
顶层设计完了之后就是实现问题了,逆序数我用的是线段树。寻找超越飞船我也用了线段树,把每段线段当作一个点,然后每次查询最小,单点更新。
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int maxn1 = 250010; const int maxn2 = 110; const int mod = 1000000; struct tree1{ int l , r , sum; }a1[4*maxn2]; struct plane{ int x , v; }P[maxn1]; struct tree2{ int l , r , Max; }a2[4*maxn1]; struct Node{ int l , r; }node[maxn1]; int N; void build1(int l , int r , int k){ a1[k].l = l; a1[k].r = r; a1[k].sum = 0; if(l != r){ int mid = (l+r)/2; build1(l , mid , 2*k); build1(mid+1 , r , 2*k+1); } } void add1(int l , int r , int k){ if(l <= a1[k].l && a1[k].r <= r) a1[k].sum++; else{ int mid = (a1[k].l+a1[k].r)/2; if(mid >= r) add1(l , r , 2*k); else add1(l , r , 2*k+1); a1[k].sum = (a1[2*k].sum+a1[2*k+1].sum)%mod; } } int query1(int l , int r , int k){ if(l <= a1[k].l && a1[k].r <= r) return a1[k].sum; else{ int mid = (a1[k].l+a1[k].r)/2; if(mid >= r) return query1(l , r , 2*k)%mod; else if(l > mid) return query1(l , r , 2*k+1)%mod; else return (query1(l , mid , 2*k)+query1(mid+1 , r , 2*k+1))%mod; } } void pushup(int k){ if(a2[2*k].Max == -1 && a2[2*k+1].Max == -1) a2[k].Max = -1; else if(a2[2*k].Max == -1) a2[k].Max = a2[2*k+1].Max; else if(a2[2*k+1].Max == -1) a2[k].Max = a2[2*k].Max; else{ int lson = a2[2*k].Max , rson = a2[2*k+1].Max; int lnode = (P[node[lson].r].v-P[node[lson].l].v)*(P[node[rson].r].x-P[node[rson].l].x); int rnode = (P[node[rson].r].v-P[node[rson].l].v)*(P[node[lson].r].x-P[node[lson].l].x); if(lnode <= rnode) a2[k].Max = a2[2*k].Max; else a2[k].Max = a2[2*k+1].Max; } } void build2(int l , int r , int k){ a2[k].l = l; a2[k].r = r; a2[k].Max = -1; if(l == r){ if(P[node[l].l].v <= P[node[l].r].v) a2[k].Max = -1; else a2[k].Max = l; }else{ int mid = (l+r)/2; build2(l , mid , 2*k); build2(mid+1 , r , 2*k+1); pushup(k); } } void update(int l , int r , int k){ if(l <= a2[k].l && a2[k].r <= r){ if(P[node[l].l].v <= P[node[l].r].v) a2[k].Max = -1; else a2[k].Max = l; }else{ int mid = (a2[k].l+a2[k].r)/2; if(r <= mid) update(l , r , 2*k); else update(l , r , 2*k+1); pushup(k); } } void computing(){ for(int i = 1; i < N; i++){ node[i].l = i; node[i].r = i+1; } build2(1 , N-1 , 1); int cnt = 0; while(cnt < 10000){ if(a2[1].Max == -1) break; int m = a2[1].Max; printf("%d %d\n" , node[m].l , node[m].r); swap(node[m].l , node[m].r); update(m , m , 1); if(m-1 >= 1){ node[m-1].r = node[m].l; update(m-1 , m-1 , 1); } if(m+1 < N){ node[m+1].l = node[m].r; update(m+1 , m+1 , 1); } cnt++; } } void readcase(){ build1(1 , 100 , 1); int ans = 0; for(int i = 1; i <= N; i++){ scanf("%d%d" , &P[i].x , &P[i].v); ans = (ans+query1(P[i].v+1 , 100 , 1))%mod; add1(P[i].v , P[i].v , 1); } printf("%d\n" , ans); if(ans != 0) computing(); } int main(){ while(~scanf("%d" , &N)){ readcase(); } return 0; }
poj 2274 The Race(逆序数+线段树),布布扣,bubuko.com
原文地址:http://blog.csdn.net/u011836218/article/details/38736259