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等待入栈:
- 栈为空,则入栈
- 栈顶元素与A在给定时间内不相遇,入栈
- 栈顶元素与A在给定时间内相遇,将栈顶元素出栈,并在两者中点新建一个组,人为原先两组的人的并,标记为静止组。将栈顶元素和A中所有的人的位置更改为新位置。
由于定理1,该方法必然会使所有相遇“顺序”发生,因而不会出现抢人的问题。
人处于哪一组可以用并查集实现,注意对于无法与其他元素相遇的元素,输出时要特别处理。复杂度通过摊还分析,容易得知为
示例代码
#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
- luogu解题报告:P3407散步【栈】【奇技淫巧】
- luogu解题报告:HNOI2012永无乡
- NOIp1998PJ/Luogu P1010 幂次方 解题报告
- Luogu T1125 why_always_I_like_素数 解题报告
- NOIp2015TG/Luogu P2661 信息传递 解题报告
- Luogu P1823 音乐会的等待 解题报告
- luogu解题报告:P3391文艺平衡树
- luogu解题报告:P2178[NOI2015]品酒大会
- 火星人(Luogu P1088)解题报告
- 洛谷 P3407 散步 (二分答案+判定 或 模拟)
- 洛谷 1294 高手去散步 搜索?图论? 解题报告
- Luogu P1294 高手去散步
- luogu P1294 高手去散步
- NOIp2010TG/Luogu P1514 引水入城 解题报告
- Luogu P1569 KC与龙珠 解题报告
- NOI2002/Luogu P1196 银河英雄传说 解题报告
- NOIp2012TG/Luogu P1082 同余方程 解题报告
- NOIp2009TG T2/Luogu P1072 Hankson的趣味题 解题报告
- MySQL执行计划解读
- 对象的行为
- yii2学习笔记——yii2引入微信API
- 怎样阅读一本书——概述
- lamp环境源码安装文档(centos7我已经试验过,没问题)
- luogu解题报告:P3407散步【栈】【奇技淫巧】
- Java基础
- DNS原理及实战配置指南
- Hadoop系列-HDFS HA高可用集群
- 51nod 1133 不重叠的线段
- 过滤器
- 怎样阅读一本书——阅读的层次
- 奇偶数分离
- 第三篇 设计模式之抽象工厂方法模式