luogu解题报告:P3407散步【栈】【奇技淫巧】

来源:互联网 发布:卷积网络 pooling 编辑:程序博客网 时间:2024/05/29 09:44

题目见https://www.luogu.org/problem/show?pid=3407

分析

定理一:如果从西向东顺次有A,B,C三人,再A与C发生相遇(如果会)之前,必然会有B先和A或B先和C相遇。这是显然的。换句话说,不会出现跨过某人发生相遇。这是一个明显的操作具有顺序性的提示。

定理二:把若干个运动状态相同的人看作一“组”,则每一组有且只有三种情况:静止,向西运动,向东运动。

定理三:对于任意相邻的两个组,他们相遇当且仅当他们相向而行或一个静止一个朝向另一个运动,且运动时间少于T。如果相向而行,相遇点在两组正中;否则在静止的那一组。

至此可以有一个大概的思路:维护一种元素A,包含其位置,运动状态,人。维护一个此元素栈,所有人开始视为独立的元素,自西向东按顺序入栈,如果一个元素A等待入栈:

  1. 栈为空,则入栈
  2. 栈顶元素与A在给定时间内不相遇,入栈
  3. 栈顶元素与A在给定时间内相遇,将栈顶元素出栈,并在两者中点新建一个组,人为原先两组的人的并,标记为静止组。将栈顶元素和A中所有的人的位置更改为新位置。

由于定理1,该方法必然会使所有相遇“顺序”发生,因而不会出现抢人的问题。

人处于哪一组可以用并查集实现,注意对于无法与其他元素相遇的元素,输出时要特别处理。复杂度通过摊还分析,容易得知为O(nα(n))

示例代码

#include <iostream>#include <cstdio>#include <cstring>#include <stack>using namespace std;typedef long long ll;int fa[100005];inline int father(int i){    return fa[i]?fa[i] = father(fa[i]):i;}inline void link(int i, int j){    if (father(i) != father(j))         fa[father(i)] = father(j);}ll pos[100005];struct sb {    ll first;    int second;    int pos;    void print()    {        printf("-- %lld %d %d --\n", first, second, pos);    }};sb make_p(ll a, int b, int c){    sb n;    n.first = a;    n.second = b;    n.pos = c;    //cout << n.first << " " << n.second << " " << n.pos << endl;    //n.print();    return n;}sb sbs[100005];sb sav[100005];int did[100005];ll n, t, q;stack<sb> stk;bool meet(const sb &a, const sb &b){    if ((a.second == 0 && b.second == 2 && b.first - a.first <= t)    || (a.second == 1 && b.second == 0 && b.first - a.first <= t)    || (a.second == 1 && b.second == 2 && b.first - a.first <= 2*t)    ) return true;    return false;}ll place(const sb &a, const sb &b){    if (a.second == 0) return a.first;    if (b.second == 0) return b.first;    return (a.first+b.first)>>1;}int main(){    memset(fa, 0, sizeof fa);    memset(did, 0, sizeof did);    make_p(1, -2, 3);    scanf("%lld%lld%lld", &n, &t, &q);    for (int i = 1; i <= n; i++) {        ll a; int b;        scanf("%lld%d", &a, &b);        sbs[i] = make_p(a, b, i);        sav[i] = sbs[i];        //make_p(a, b, i).print();        pos[i] = a;    }    for (int i = 1; i <= n; i++) {        while (1) {            if (stk.empty() || !meet(stk.top(), sbs[i])) {                //stk.push(sbs[i]);                break;            } else {                sb tmp = stk.top(); stk.pop();                link(tmp.pos, sbs[i].pos);                sb new_sb = make_p(place(tmp, sbs[i]), 0, tmp.pos);                pos[father(tmp.pos)] = place(tmp, sbs[i]);                did[i] = 1;                did[tmp.pos] = 1;                sbs[i] = new_sb;            }        }        stk.push(sbs[i]);        /*if (!stk.empty())            stk.top().print();        else            puts("--nil--");*/    }    for (int i = 1; i <= q; i++) {        int a;        scanf("%d", &a);        if (did[a] == 0) {            if (sav[a].second == 1)                printf("%lld\n", pos[father(a)]+t);            else                printf("%lld\n", pos[father(a)]-t);        }        else            printf("%lld\n", pos[father(a)]);    }    return 0;}
0 0
原创粉丝点击