COCI CONTEST #3 29.11.2014 KAMIONI
2015-09-11 21:41
351 查看
题目描述
A国的城市可以看做是数轴上的整数点,有n辆卡车在公路上往返行驶,它们只能在到达某个城市才能掉头,掉头是不需要时间的,而且卡车在途中不能停下来。这n辆卡车初始时可能位于不同的城市,在某个时刻它们同时出发,每辆卡车每分钟可以到达下一个城市,即每分钟可以行使单位1的路程。当卡车到达终点时,它将会进入时空隧道,瞬间消失。给出每辆卡车的行驶的路径,即卡车的起点、中途每次掉头的点及终点,有m次查询,每次查询指定两辆卡车,问它们一共相遇多少次?注意:卡车相遇点不一定是城市。另外,相遇时其中一辆卡车进入时光隧道不算相遇;起始瞬间两辆卡车位于同一地点不算相遇;其中一辆卡车正好掉头不算相遇。
n<=100000,m<100000,城市的编号在[1,10^9]之间。每辆卡车路径掉头的次数不超过3*10^5;所有卡车掉头的总次数之和不超过3*10^5.
输入:
第一行两个整数n,m,表示卡车的数量和查询的次数。接下来n行,每行的第一个数为Ki(2<=Ki<=3*10^5),表示卡车的路径包含Ki个点,接下来有Ki个数,每个数在区间[1,10^9]之间,按顺序表示卡车行驶时经过的城市,包括起点和终点。
所有Ki之和超过3*10^5
接下来m行,每行两个整数,表示查询这两辆卡车一共相遇多少次。
输出:
对每次查询,输出一个整数,表示它们相遇次数。50%的数据,n<100,Ki<1000,m<1000
思路:
首先我们应该将每一辆车的转折点按照发生时间来排序。讲每一个查询都保存下来,当然重复的我们只留一个去计算,其余的我们应当保存在一个与保留的那一个有关的数据结构里。顺便提一下,做这道题是一定要估计好空间复杂度,防止被卡空间。然后在保存一个询问的时候只保存在拐点少的那个的名下。然后枚举每一个拐点就可以了。然后我们分析时间复杂度:
如果某个卡车的转折点小于k√个,即使和它名下存的查询关系多于k√个,但是它在转折点数组中的出现次数一定小于k√次。
如果某个卡车的转折点多于k√个,即使它在转折点一定枚举k√+次,但是和它有查询关系的卡车一定小于k√个。
通过以上分析,我们知道均摊的时间复杂度不会超过k√个。所以总的时间复杂度就是O(k32).
代码:(用hash表实现去重以及保存询问)
#include<algorithm> #include<map> #include<cstdio> #include<vector> #define LL long long #define PII pair<int, int> const int MAXN = 300010; using namespace std; struct event { int id, p, dir; //id->trucks' number; p->position; dir->direction LL time; bool operator < (const event &rhs) const { if(time != rhs.time) return time < rhs.time; return dir > rhs.dir; } event(){} event(int a, int b, int c, LL d){id = a, p = b, dir = c; time = d;} }; int h[2000000]; PII hsh[2000000]; int hshit(PII t) { int p = 1LL * (t.second - t.first) * t.first * 12580 % 2000000; while(h[p] && hsh[p] != t) p = (p + 1) % 2000000; ++ h[p]; hsh[p] = t; return p; } struct query { int id, was_left, qid; query() {} query(int a, int b, int c) { id = a; was_left = b; qid = c; } }; struct List { int id, num; vector<int> index; List *next; List(){next = NULL; id = num = -1;} }*Adj[MAXN], *hs[2000000]; struct truck { int k, p, dir; LL time; vector<query> queries; } trucks[MAXN]; inline void GET(int &n) { n = 0; char c; do c = getchar(); while(c > '9' || c < '0'); while(c >= '0' && c <= '9') {n = n*10 + c - '0'; c = getchar();} } int n, m; void init(event &e) { trucks[e.id].p = e.p; trucks[e.id].dir = e.dir; trucks[e.id].time = e.time; } int check(const truck &a, const truck &b, LL pretime, int predir) { if (!b.dir && pretime >= b.time) return 0; int b_pos, a_pos; if (!b.dir) { b_pos = b.p; a_pos = (a.time - b.time) *(-predir) + a.p; } else { a_pos = a.p; b_pos = (a.time - b.time) * b.dir + b.p; } return b_pos < a_pos ? -1 : 1; } int ans[MAXN]; void solve(const truck &t, query &q, LL pretime, int predir) { int is_left = check(t, trucks[q.id], pretime, predir); ans[q.qid] += (q.was_left * is_left == -1); q.was_left = is_left; } int main() { vector<event> events; GET(n); GET(m); int x, newx; LL tsum; event e; for(int i = 0; i < n; ++ i) { tsum = 0; GET(trucks[i].k); GET(x); for(int j = 0; j < trucks[i].k - 1; ++ j) { GET(newx); e = event(i, x, x < newx ? 1 : -1, tsum); if(!j) init(e); else events.push_back(e); tsum += abs(x - newx); x = newx; } e = event(i, x, 0, tsum); events.push_back(e); } int a, b; for(int i = 0; i < m; i ++) { GET(a); GET(b); -- a; -- b; if(a > b) swap(a, b); int t = hshit(PII(a, b)); if(h[t] > 1) { hs[t]->num ++; hs[t]->index.push_back(i); continue; } else { if(!Adj[a]) { Adj[a] = new List(); Adj[a]->num = 1; Adj[a]->id = b; hs[t] = Adj[a]; hs[t]->index.push_back(i); } else { List *p = new List(); p->next = Adj[a]->next; p->id = b; p->num = 1; Adj[a]->next = p; hs[t] = p; hs[t]->index.push_back(i); } } if (trucks[a].k > trucks[b].k) swap(a, b); trucks[a].queries.push_back(query(b, trucks[b].p < trucks[a].p ? -1 : 1, i)); } sort(events.begin(), events.end()); for(int i = 0; i < events.size(); i ++) { e = events[i]; LL prev_time = trucks[e.id].time; int prev_dir = trucks[e.id].dir; init(e); for(int i = 0; i < trucks[e.id].queries.size(); i ++) { query &q = trucks[e.id].queries[i]; solve(trucks[e.id], q, prev_time, prev_dir); } } int sz; for(int i = 0; i < n; i ++) for(List *p = Adj[i]; p; p = p->next) { sz = p->index.size(); for(int j = 1; j < sz; j ++) ans[p->index[j]] = ans[p->index[0]]; } for(int i = 0; i < m; ++i) printf("%d\n", ans[i]); return 0; }
相关文章推荐
- uva 1310 - One-way traffic(连通分量)
- LeetCode -- Implement Queue using Stacks
- 第六章 视频传输技术
- 腾迅股票数据接口 http/javascript
- OpenGL之纹理映射(一)
- 绘画板
- 从新定义线性链表及其基本操作
- python 多进程编程
- ios-视频播放
- pickerView显示
- android之gradle构建工具学习之路(一)
- ROS(6):ROS安装rviz模拟器
- uva 1265 - Tour Belt(生成树)
- LeetCode -- Compare Version Numbers
- (4.1.35.3)Android平台程序崩溃的类型及原因列举
- hdu5029Relief grain 线段树
- EJB远程访问和本地访问方式
- Python
- CocoaPods的安装与使用,以及添加ReactiveCocoa
- 项目11.3如何买玫瑰