再考虑如何把操作加入。一个基本的思想是,操作时我们不显式地更改指令,而是尝试更改坐标系。对于平移操作,我们完全可以先将点P 沿着逆方向平移,完成指令后再沿着正方向平移回来。写成矩阵形式就是把原来的指令矩阵 M 变成 DMD−1,其中 D 为沿着向量 (u,v) 平移对应的矩阵。这个很容易往线段树上打个乘法标记维护。对于翻折操作也是差不多的,我们可以尝试先把点翻过去,执行完指令再翻回来。需要注意的是在点翻到镜像位置之后,原有的旋转操作就需要把逆时针转变成顺时针转了。不过这还是很好办,我们对旋转维护 M,M′ 分别表示逆时针、顺时针转对应的矩阵即可。那么翻折操作就是把 M 变为 RM′R,把 M′ 变为 RMR,其中 R 是翻折对应的矩阵。
这题没怎么卡精度,应该不需要 long double 就能过。
3|0代码
// ubsan: undefined// accoders/*
(x, y) (p, q)
(x - p, y - q)
l = sqrt((x - p)^2 + (y - q)^2)
(l * cos(A + B), l * sin(A + B))
(l * (cos(A) * cos(B) - sin(A) * sin(B)), l * (sin(A) * cos(B) + sin(B) * cos(A)))
((x - p) * cos(B) - (y - q) * sin(B), (y - q) * cos(B) + (x - p) * sin(B))
(x * cos(B) - y * sin(B) + (1 - cos(B)) * p + q * sin(B), x * sin(B) + y * cos(B) - p * sin(B) + q* (1 -
cos(B)))
(m, n) ax + by + c = 0
-bx + ay + z = 0
z = bx - ay
z = bm - an
-bx + ay + (bm - an) = 0
xby + ((a^2) / b)y + (bm - an) * (a / b) + c = 0
((a^2 + b^2) / b)y + am - (a^2 / b) * n + c = 0
y = ((a^2)n - abm - bc) / (a^2 + b^2)
ax + (b^2 / a)x - (bm - an) * (b / a) + c = 0
((a^2 + b^2) / a)x - (b^2 / a)m + bn + c = 0
x = (-abn + (b^2)m - ac) / (a^2 + b^2)
x = (-uvn + (v^2)m - uw) / (u^2 + v^2)
y = ((u^2)n - uvm - vw) / (u^2 + v^2)
2x - m = (-2uvn + ((v^2) - (u^2))m - 2uw) / (u^2 + v^2)
2y - n = (((u^2) - (v^2))n - 2uvm - 2vw) / (u^2 + v^2)
*/#include<cstdio>#include<algorithm>#include<random>#include<cmath>usingnamespace std;
#define MAXN 100000#define PI 3.14159265358979328346264structpolynomial {
double a = 0, b = 0, c = 0;
polynomial() {}
polynomial(double A, double B, double C) {
a = A;
b = B;
c = C;
}
};
mt19937 r(20061206);
structfhq {
int son[2];
bool lazy = 0;
pair<polynomial, polynomial> v[2], sum[2], lazy1, lazy2;
int num = 0;
int key = r();
} s[MAXN + 5];
int rt;
int tot = 0;
intnewfhq(pair<polynomial, polynomial> v1, pair<polynomial, polynomial> v2){
++tot;
s[tot].son[0] = s[tot].son[1] = 0;
s[tot].v[0] = s[tot].sum[0] = v1;
s[tot].v[1] = s[tot].sum[1] = v2;
s[tot].lazy = 0;
s[tot].lazy1 = make_pair(polynomial(1, 0, 0), polynomial(0, 1, 0));
s[tot].lazy2 = make_pair(polynomial(1, 0, 0), polynomial(0, 1, 0));
s[tot].num = 1;
return tot;
}
pair<polynomial, polynomial> operator*(pair<polynomial, polynomial> a, pair<polynomial, polynomial> b) {
pair<polynomial, polynomial> c;
c.first.a = a.first.a * b.first.a + a.second.a * b.first.b;
c.first.b = a.first.b * b.first.a + a.second.b * b.first.b;
c.first.c = a.first.c * b.first.a + a.second.c * b.first.b + b.first.c;
c.second.a = a.first.a * b.second.a + a.second.a * b.second.b;
c.second.b = a.first.b * b.second.a + a.second.b * b.second.b;
c.second.c = a.first.c * b.second.a + a.second.c * b.second.b + b.second.c;
return c;
}
voiddownload(int p){
if (!p) {
return;
}
if (s[p].son[0]) {
s[s[p].son[0]].sum[0] = s[p].lazy1 * s[s[p].son[0]].sum[0] * s[p].lazy2;
s[s[p].son[0]].v[0] = s[p].lazy1 * s[s[p].son[0]].v[0] * s[p].lazy2;
s[s[p].son[0]].sum[1] = s[p].lazy1 * s[s[p].son[0]].sum[1] * s[p].lazy2;
s[s[p].son[0]].v[1] = s[p].lazy1 * s[s[p].son[0]].v[1] * s[p].lazy2;
s[s[p].son[0]].lazy1 = s[p].lazy1 * s[s[p].son[0]].lazy1;
s[s[p].son[0]].lazy2 = s[s[p].son[0]].lazy2 * s[p].lazy2;
if (s[p].lazy) {
swap(s[s[p].son[0]].sum[0], s[s[p].son[0]].sum[1]);
swap(s[s[p].son[0]].v[0], s[s[p].son[0]].v[1]);
s[s[p].son[0]].lazy ^= 1;
}
}
if (s[p].son[1]) {
s[s[p].son[1]].sum[0] = s[p].lazy1 * s[s[p].son[1]].sum[0] * s[p].lazy2;
s[s[p].son[1]].v[0] = s[p].lazy1 * s[s[p].son[1]].v[0] * s[p].lazy2;
s[s[p].son[1]].sum[1] = s[p].lazy1 * s[s[p].son[1]].sum[1] * s[p].lazy2;
s[s[p].son[1]].v[1] = s[p].lazy1 * s[s[p].son[1]].v[1] * s[p].lazy2;
s[s[p].son[1]].lazy1 = s[p].lazy1 * s[s[p].son[1]].lazy1;
s[s[p].son[1]].lazy2 = s[s[p].son[1]].lazy2 * s[p].lazy2;
if (s[p].lazy) {
swap(s[s[p].son[1]].sum[0], s[s[p].son[1]].sum[1]);
swap(s[s[p].son[1]].v[0], s[s[p].son[1]].v[1]);
s[s[p].son[1]].lazy ^= 1;
}
}
s[p].lazy1 = make_pair(polynomial(1, 0, 0), polynomial(0, 1, 0));
s[p].lazy2 = make_pair(polynomial(1, 0, 0), polynomial(0, 1, 0));
s[p].lazy = 0;
}
voidupload(int p){
s[p].num = s[s[p].son[0]].num + 1 + s[s[p].son[1]].num;
if (s[p].son[0]) {
s[p].sum[0] = s[s[p].son[0]].sum[0] * s[p].v[0];
s[p].sum[1] = s[s[p].son[0]].sum[1] * s[p].v[1];
} else {
s[p].sum[0] = s[p].v[0];
s[p].sum[1] = s[p].v[1];
}
if (s[p].son[1]) {
s[p].sum[0] = s[p].sum[0] * s[s[p].son[1]].sum[0];
s[p].sum[1] = s[p].sum[1] * s[s[p].son[1]].sum[1];
}
}
voidsplit(int p, int &l, int &r, int loc){
if (!p) {
l = r = 0;
return;
}
download(p);
if (s[s[p].son[0]].num + 1 < loc) {
l = p;
split(s[p].son[1], s[l].son[1], r, loc - (s[s[p].son[0]].num + 1));
upload(l);
} else {
r = p;
split(s[p].son[0], l, s[r].son[0], loc);
upload(r);
}
}
intmerge(int l, int r){
if (l == 0 || r == 0) {
return l + r;
}
if (s[l].key > s[r].key) {
download(l);
s[l].son[1] = merge(s[l].son[1], r);
upload(l);
return l;
} else {
download(r);
s[r].son[0] = merge(l, s[r].son[0]);
upload(r);
return r;
}
}
voidinsert(pair<polynomial, polynomial> v1, pair<polynomial, polynomial> v2, int loc){
int h, t;
split(rt, h, t, loc);
rt = merge(h, merge(newfhq(v1, v2), t));
}
voidchange(int l, int r, pair<polynomial, polynomial> v1, pair<polynomial, polynomial> v2, bool flag){
int h, mid, t;
split(rt, h, t, r + 1);
split(h, h, mid, l);
s[mid].lazy1 = v1 * s[mid].lazy1;
s[mid].lazy2 = s[mid].lazy2 * v2;
s[mid].sum[0] = v1 * s[mid].sum[0] * v2;
s[mid].v[0] = v1 * s[mid].v[0] * v2;
s[mid].sum[1] = v1 * s[mid].sum[1] * v2;
s[mid].v[1] = v1 * s[mid].v[1] * v2;
if (flag) {
s[mid].lazy ^= 1;
swap(s[mid].v[0], s[mid].v[1]);
swap(s[mid].sum[0], s[mid].sum[1]);
}
rt = merge(h, merge(mid, t));
}
pair<double, double> ask(int l, int r, double x, double y){
int h, mid, t;
pair<double, double> ans;
split(rt, h, t, r + 1);
split(h, h, mid, l);
ans.first = s[mid].sum[0].first.a * x + s[mid].sum[0].first.b * y + s[mid].sum[0].first.c;
ans.second = s[mid].sum[0].second.a * x + s[mid].sum[0].second.b * y + s[mid].sum[0].second.c;
rt = merge(h, merge(mid, t));
return ans;
}
intmain(){
freopen("point.in", "r", stdin);
freopen("point.out", "w", stdout);
int n, m;
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++) {
int opt;
scanf("%d", &opt);
if (opt == 1) {
double u, v, t;
double A;
scanf("%lf %lf %lf", &u, &v, &t);
A = t * PI / 1800;
pair<polynomial, polynomial> v1 =
make_pair(polynomial(cos(A), -sin(A), (1 - cos(A)) * u + v * sin(A)),
polynomial(sin(A), cos(A), -u * sin(A) + v * (1 - cos(A))));
pair<polynomial, polynomial> v2 =
make_pair(polynomial(cos(-A), -sin(-A), (1 - cos(-A)) * u + v * sin(-A)),
polynomial(sin(-A), cos(-A), -u * sin(-A) + v * (1 - cos(-A))));
insert(v1, v2, i);
} elseif (opt == 2) {
double u, v, w;
scanf("%lf %lf %lf", &u, &v, &w);
insert(make_pair(polynomial((v * v) / (u * u + v * v), -(u * v) / (u * u + v * v),
-u * w / (u * u + v * v)),
polynomial(-u * v / (u * u + v * v), (u * u) / (u * u + v * v),
-v * w / (u * u + v * v))),
make_pair(polynomial((v * v) / (u * u + v * v), -(u * v) / (u * u + v * v),
-u * w / (u * u + v * v)),
polynomial(-u * v / (u * u + v * v), (u * u) / (u * u + v * v),
-v * w / (u * u + v * v))),
i);
}
}
for (int i = 1; i <= m; i++) {
int opt;
scanf("%d", &opt);
if (opt == 1) {
int l, r;
double u, v;
scanf("%d %d %lf %lf", &l, &r, &u, &v);
change(l, r, make_pair(polynomial(1, 0, -u), polynomial(0, 1, -v)),
make_pair(polynomial(1, 0, u), polynomial(0, 1, v)), 0);
} elseif (opt == 2) {
int l, r;
double u, v, w;
scanf("%d %d %lf %lf %lf", &l, &r, &u, &v, &w);
pair<polynomial, polynomial> value =
make_pair(polynomial(((v * v) - (u * u)) / (u * u + v * v), -2 * u * v / (u * u + v * v),
-2 * u * w / (u * u + v * v)),
polynomial(-2 * u * v / (u * u + v * v), ((u * u) - (v * v)) / (u * u + v * v),
-2 * v * w / (u * u + v * v)));
change(l, r, value, value, 1);
} else {
int l, r;
double x, y;
pair<double, double> ans;
scanf("%d %d %lf %lf", &l, &r, &x, &y);
ans = ask(l, r, x, y);
printf("%.8lf %.8lf\n", ans.first, ans.second);
}
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】