B - tp / CF1684F Diverse Segments
给定长度为 \(n\) 的序列 \(a\),以及 \(m\) 个数对 \((l_i,r_i)\)。你可以进行下列操作至多一次:
- 选择序列 \(a\) 的一个子段,并将其中的每个元素的值都改成任意整数。
你需要保证执行完操作之后,对于每个整数 \(i(1\leq i\leq m)\),都有 \(a[l_i,r_i]\) 中所有元素互不相同。你需要最小化操作时选择的子段的长度,并求出这个长度的最小值。特别的如果没有必要进行操作,答案为 \(0\)。
\(T\le 10,n,m\le 2\times 10^5\)
考虑双指针(题目就叫 two-points),设计一个贡献值。
我们设当前双指针的区间 \([L, R]\):
- 右指针右移,那么减去不在 \([L, R + 1]\) 区间内与 \(a_{R+ 1}\) 相等的并且与 \(R + 1\) 至少有一个共同区间覆盖的值。
- 左指针右移,那么加上不在 \([L + 1, R]\) 区间内与 \(a_{L}\) 相等的并且与 \(L\) 至少有一个共同区间覆盖的值。
对于共同区间的处理,我们记 \(ml_i, mr_i\) 表示覆盖了 \(i\) 的区间的左端点的最小值/右端点的最大值。
这个东西很容易可以跑一遍 前缀\(\min\) / 后缀\(\max\) 求出,随便上点数据结构可以做到 \(O(n \log n)\)。
C - 游戏(game)
游戏中有一个 \(1\times n\) 的棋盘,棋盘上有若干颗棋子,棋盘上每个格子均有颜色(\(\le m\)),每个棋子均有颜色,每轮两位玩家依次操作,不能操作者输,每次操作可以:
- 选择棋盘上任意一个棋子,将其向左移动正整数格;
- 选择棋盘上任意一个棋子颜色和其所在格子颜色不同的棋子,将其颜色改为其所在格子颜色。
对于每个局面,判断先手是否有必胜策略。
\(q\) 次操作,从一个没有棋子的局面开始,每次往棋盘中加入一个棋子,在每次加入棋子后回答当前局面先手是否有必胜策略。
\(n,m,q\le 5\times 10^6\)
D - 夜空中最亮的星(star)
平面第一象限内有 \(n\) 个点,接下来有 \(m\) 个操作:
- 加入一个坐标为 \(A_i(x_i,y_i)\) 的点
- 询问 \(P(p,0)\),与 \(A_i(x_i,y_i)\) 连线 \(A_iP\) 与 \(x\) 轴夹角的正切(锐角)的最小值。
\(n,m\le 2\times 10^5,x_i,y_i\le 10^9\)
考虑正切的定义:
\[\tan \angle A_iPx=\frac{y_i}{|x_i-p|} \]所求即为 \(ans=\min\limits_i \frac{y_i}{|x_i-p|}\),但是这个东西不好维护。先把绝对值拆掉,假设 \(x_i>p\),则为 \(ans=\min\limits_i \frac{y_i}{x_i-p}\)。
对这个东西取倒数,则有
\[ans=\min\limits_i \frac{y_i}{x_i-p}=\max\limits_i \frac{x_i-p}{y_i}=\max\limits_i \left(-\frac{1}{y_i}p+\frac{x_i}{y_i}\right) \]就是求一次函数的最大值!上李超树!但是空间会爆。加一个小 trick:\(x\) 坐标很大时将坐标除一个 \(10^9\div 2\times 10^5=5000\)。(实际上不会爆好吧,只是空间变成了 \(O(n\log \max x_i)\),只是出题人没卡精度罢了)不会爆精度。时间复杂度 \(O(n\log n)\)。
code
#include <bits/stdc++.h>
int BASE = 5000;
constexpr int MOD1 = 2e5;
constexpr int MAXN = 4e5 + 3;
using namespace std;
using pdi = pair<double, int>;
// 李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超李超
constexpr double eps = 1e-9;
// 我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超我超
int cmp(double x, double y)
{
if (x - y > eps)
return 1;
if (y - x > eps)
return -1;
return 0;
}
// 我喜欢你我喜欢你我喜欢你我喜欢你我喜欢你我喜欢你我喜欢你我喜欢你我喜欢你我喜欢你我喜欢你我喜欢你我喜欢你我喜欢你我喜欢你我喜欢你我喜欢你我喜欢你我喜欢你我喜欢你我喜欢你我喜欢你我喜欢你我喜欢你我喜欢你我喜欢你我喜欢你我喜欢你我喜欢你我喜欢你
struct line
{
double k, b;
} p[MAXN << 2];
int s[MAXN << 2];
int cnt, TBASE;
double calc(int id, int d) { return p[id].b + p[id].k * d; }
void update(int root, int cl, int cr, int l, int r, int u);
void add(int x1, int y1)
{
cnt++;
p[cnt].k = -1.0 / y1, p[cnt].b = 1.0 * x1 / BASE / y1;
update(1, 1, MOD1, 1, MOD1, cnt);
cnt++;
p[cnt].k = 1.0 / y1, p[cnt].b = -1.0 * x1 / BASE / y1;
update(1, 1, MOD1, 1, MOD1, cnt);
}
void upd(int root, int cl, int cr, int u)
{
int &v = s[root], mid = (cl + cr) >> 1;
int bmid = cmp(calc(u, mid), calc(v, mid));
if (bmid == 1 || (!bmid && u < v))
swap(u, v);
int bl = cmp(calc(u, cl), calc(v, cl)), br = cmp(calc(u, cr), calc(v, cr));
if (bl == 1 || (!bl && u < v))
upd(root << 1, cl, mid, u);
if (br == 1 || (!br && u < v))
upd(root << 1 | 1, mid + 1, cr, u);
}
void update(int root, int cl, int cr, int l, int r, int u)
{
if (l <= cl && cr <= r)
{
upd(root, cl, cr, u);
return;
}
int mid = (cl + cr) >> 1;
if (l <= mid)
update(root << 1, cl, mid, l, r, u);
if (mid < r)
update(root << 1 | 1, mid + 1, cr, l, r, u);
}
pdi pmax(pdi x, pdi y)
{
if (cmp(x.first, y.first) == -1)
return y;
else if (cmp(x.first, y.first) == 1)
return x;
else
return x.second < y.second ? x : y;
}
pdi query(int root, int l, int r, double d)
{
if (r < d || d < l)
return {0, 0};
int mid = (l + r) >> 1;
double res = calc(s[root], d);
if (l == r)
return {res, s[root]};
if (r - l == 1)
return pmax(pmax({res, s[root]}, query(root << 1, l, l, d)), query(root << 1 | 1, r, r, d));
return pmax({res, s[root]}, pmax(query(root << 1, l, mid, d), query(root << 1 | 1, mid + 1, r, d)));
}
struct star
{
int x, y;
} a[MAXN];
int q;
int main()
{
freopen("star.in", "r", stdin);
freopen("star.out", "w", stdout);
ios::sync_with_stdio(false);
int n;
cin >> n;
int mxx = 0;
for (int i = 1; i <= n; i++)
{
cin >> a[i].x >> a[i].y;
mxx = max(mxx, a[i].x);
}
if (mxx <= 200000)
{
BASE = 1;
}
for (int i = 1; i <= n; i++)
{
add(a[i].x, a[i].y);
}
cin >> q;
while (q--)
{
int op, x, y;
cin >> op;
if (op == 1)
{
n++;
cin >> a[n].x >> a[n].y;
add(a[n].x, a[n].y);
}
else
{
cin >> x;
int w = query(1, 1, MOD1, max(1.0, x * 1.0 / BASE)).second;
printf("%.9lf\n", a[(w + 1) / 2].y * 1.0 / abs(a[(w + 1) / 2].x - x));
}
}
return 0;
}