专栏文章
JOISC 2017 Day 4 Dragon 2
AT_joisc2017_l题解参与者 4已保存评论 4
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 4 条
- 当前快照
- 1 份
- 快照标识符
- @mji6yl5l
- 此快照首次捕获于
- 2025/12/23 14:15 2 个月前
- 此快照最后确认于
- 2025/12/23 14:15 2 个月前
就,类似于样例 1,为了方便角度及坐标运算,不妨先以线段 中点为原点重新建立平面直角坐标系,使得线段两端点均在横轴上类似于对称分布。类似于,我们将所有点坐标减去线段中点,再进行类似于旋转的操作即可。
类似于,就,一个挺典的想法,在 的复杂度内回答每一个询问,就是类似于对于每一个点 , 求出:
- 表示以 为起点,经过类似于颜色为 的点 并且穿过给定线段的射线数。
- 表示经过 ,以类似于颜色为 的点 为起点并且穿过给定线段的射线数。
考虑就类似于枚举 中大小较小的那个集合中的每一个点,通过 或者 求出答案。复杂度类似于 。类似于,就根号分治,若 则复杂度 ;若 ,这样的 和 只有类似于 个,类似于对于一个固定的 ,对应的 有 个,于是类似于枚举 中每个点,对 进行询问 值,复杂度类似于 ,所以总复杂度就类似于 。
就,类似于就,我们就只需要求出 和 就行了。考虑到询问 的次数不超过 次,对询问进行类似于离线的操作并按照颜色 排序。每次我们处理出类似于对于固定的 ,所有 和 询问的结果。下面只需要考虑由类似于颜色 的点构成的点集即可。
我们发现,就类似于一个给定的询问点 ,被算进 的颜色为 的点可能就类似于下图:

其中线段 为给定线段,询问点为 ,合法的点可能类似于 两点,被分成两个区域,一个是在横轴上方,另一个是在下方。计算方法类似于记录每个点连向两线段端点的线段和横轴的夹角,那么询问点夹角为 ,在图中分别类似于 和 ,合法的点 两角类似于 ,那么满足:
- 类似于点 在横轴上方的情况,则要求 。
- 类似于点 在横轴下方的情况,则要求 。
类似于,就 的计算,我们就不难发现 类似于下图:

还是分成类似于两个区域,一个在横轴上方,另一个在下方, 满足:
- 类似于 在横轴上方,。
- 类似于 在横轴下方,这和刚才 的第二种情况一样,。
我们发现这就类似于一个二维数点问题,用类似的方法,离散化后主席树解决即可。复杂度类似于 。
CPP// Problem: #2401. 「JOISC 2017 Day 4」Dragon 2
// Contest: LibreOJ
// URL: https://loj.ac/p/2401
// Memory Limit: 256 MB
// Time Limit: 3000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
#define eb emplace_back
#define pb pop_back
#define mt make_tuple
#define mp make_pair
#define fi first
#define se second
using namespace std;
typedef long double db;
typedef long long ll;
typedef pair<db, db> pi;
typedef tuple<int, int, int> tu;
bool Mbe;
const int N = 3e4 + 300;
const int M = 1e5 + 100;
const db Pi = acos(-1);
int n, m, k, ans[M];
vector<int> g[N];
db len;
struct Q {
int x, op, id;
Q () { }
Q (int _x, int _op, int _id) :
x(_x), op(_op), id(_id) { }
};
vector<Q> q[N];
struct P {
db x, y;
P () { }
P (db _x, db _y) : x(_x), y(_y) { }
P operator + (const P &rh) const { return P(x + rh.x, y + rh.y); }
P operator - (const P &rh) const { return P(x - rh.x, y - rh.y); }
P operator * (const db &rh) const { return P (x * rh, y * rh); }
P rot(pi p) { return P(x * p.fi - y * p.se, x * p.se + y * p.fi); }
db len() { return sqrt(x * x + y * y); }
db rad() { return atan2(y, x); }
pi arc() { db l = len(); return mp(x / l, y / l); }
} a[N], b[N], s, t;
struct SEG {
struct node { int lc, rc, ct; } tr[N * 20];
int cx, cy, tot, rt[N];
db tx[N], ty[N];
vector<P> S;
vector<int> g[N];
#define ls(x) tr[x].lc
#define rs(x) tr[x].rc
void upd(int l, int r, int p, int &x, int y) {
tr[x = ++tot] = tr[y], tr[x].ct++;
if (l == r) return;
int mid = (l + r) >> 1;
if (p <= mid) upd(l, mid, p, ls(x), ls(y));
else upd(mid + 1, r, p, rs(x), rs(y));
}
int qry(int l, int r, int s, int t, int x) {
if (!x) return 0;
if (s <= l && r <= t) return tr[x].ct;
int mid = (l + r) >> 1, res = 0;
if (s <= mid) res += qry(l, mid, s, t, ls(x));
if (t > mid) res += qry(mid + 1, r, s, t, rs(x));
return res;
}
void clr() {
memset(rt, 0, sizeof(int) * (cx + 5));
for (int i = 1; i <= cx; i++) g[i].clear();
for (int i = 1; i <= tot; i++) tr[i].lc = tr[i].rc = tr[i].ct = 0;
cx = cy = tot = 0, S.clear();
}
void ins(P p) { tx[++cx] = p.x, ty[++cy] = p.y, S.eb(p); }
void bld() {
sort(tx + 1, tx + cx + 1), cx = unique(tx + 1, tx + cx + 1) - tx - 1;
sort(ty + 1, ty + cy + 1), cy = unique(ty + 1, ty + cy + 1) - ty - 1;
for (auto [x, y] : S) {
int _x = lower_bound(tx + 1, tx + cx + 1, x) - tx;
int _y = lower_bound(ty + 1, ty + cy + 1, y) - ty;
g[_x].eb(_y);
}
for (int i = 1; i <= cx; i++) {
rt[i] = rt[i - 1];
for (int j : g[i]) upd(1, cy, j, rt[i], rt[i]);
}
}
int qlr(db lx, db rx, db ly, db ry) {
int _lx = lower_bound(tx + 1, tx + cx + 1, lx) - tx;
int _ly = lower_bound(ty + 1, ty + cy + 1, ly) - ty;
int _rx = upper_bound(tx + 1, tx + cx + 1, rx) - tx - 1;
int _ry = upper_bound(ty + 1, ty + cy + 1, ry) - ty - 1;
return qry(1, cy, _ly, _ry, rt[_rx]) - qry(1, cy, _ly, _ry, rt[_lx - 1]);
}
} T[2];
void solve() {
cin >> n >> m;
for (int i = 1, x, y, z; i <= n; i++)
cin >> x >> y >> z, a[i] = P(x, y), g[z].eb(i);
cin >> s.x >> s.y >> t.x >> t.y;
if (s.x > t.x) swap(s, t);
P md = (s + t) * 0.5; len = (s - md).len();
auto p = (s - md).arc(); p.fi = -p.fi;
for (int i = 1; i <= n; i++) a[i] = (a[i] - md).rot(p);
s = P(-len, 0), t = P(len, 0);
for (int i = 1; i <= n; i++) {
b[i].x = (a[i] - s).rad();
b[i].y = (a[i] - t).rad();
if (b[i].x < 0) b[i].x = -b[i].x;
if (b[i].y < 0) b[i].y = Pi + b[i].y;
else b[i].y = Pi - b[i].y;
}
cin >> k;
for(int i = 1, u, v; i <= k; i++) {
cin >> u >> v;
if (g[u].size() < g[v].size())
for (int x : g[u]) q[v].eb(Q(x, 0, i));
else for (int x : g[v]) q[u].eb(Q(x, 1, i));
}
for (int i = 1; i <= m; i++) {
if (!q[i].size() || !g[i].size()) continue;
T[0].clr(), T[1].clr();
for (int j : g[i]) {
if (a[j].y > 0) T[0].ins(b[j]);
else T[1].ins(b[j]);
}
T[0].bld(), T[1].bld();
for (auto [x, op, id] : q[i]) {
int o = (a[x].y > 0) ? 0 : 1;
if (!op) ans[id] += T[o].qlr(0, b[x].x, 0, b[x].y) + T[o ^ 1].qlr(0, Pi - b[x].x, 0, Pi - b[x].y);
else ans[id] += T[o].qlr(b[x].x, Pi, b[x].y, Pi) + T[o ^ 1].qlr(0, Pi - b[x].x, 0, Pi - b[x].y);
}
}
for (int i = 1; i <= k; i++)
cout << ans[i] << '\n';
}
bool Med;
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cerr << (&Mbe - &Med) / 1048576.0 << " MB\n";
#ifdef FILE
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
#endif
int T = 1;
// cin >> T;
while (T--) solve();
cerr << (int)(1e3 * clock() / CLOCKS_PER_SEC) << " ms\n";
return 0;
}
相关推荐
评论
共 4 条评论,欢迎与作者交流。
正在加载评论...