您的位置:首页 > 其它

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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: