题解 P5859 【「SWTR-03」Plane Mirrors】

· · 题解

upd: 在看了 SF 的文章后修了修格式;另外题解的渲染真的很丑。。。建议点击 “在 Ta 的博客查看”。

Solution

用极角做真的更简单诶。。。
在本题解中,极角的值域默认为 (-\pi,\pi]

平面镜

设两个端点极角为 \alpha,\ \beta(\alpha < \beta).

$\therefore$ $\beta - \alpha \neq \pi

如果 \beta - \alpha > \pi, 说明平面镜跨过射线 \theta = \pi,就对应两段 [-\pi,\alpha][\beta,\pi]
否则对应一段 [\alpha,\beta]

射线

显然,若设 (x,y) 极角为 \varphi , 则对应区间 [\varphi,\varphi]

综上

具体实现先将输入中出现的极角集合 S 离散化,再用线段树维护区间加、区间求 \max 就好了。

浮点误差

$\therefore$ $\forall \alpha,\beta \in S(\alpha \neq \beta),$ 有 $|\alpha - \beta| \geq \frac{\pi}{4} - \arctan(1 - 10^{-5}) \approx 5.1 \times 10^{-6}$. $\therefore$ 离散化角度时取EPS = $10^{-10}$ 足够(其实即使不用EPS也能过qwq)。 ## Code ```cpp #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <vector> #include <queue> #include <utility> using namespace std; typedef long long ll; const int LEN = 100000; struct fastio{ int it,len; char s[LEN + 5]; fastio(){ it = len = 0; } char get(){ if(it < len) return s[it++]; it = 0, len = fread(s,1,LEN,stdin); return len ? s[it++] : EOF; } bool notend(){ char c; for(c = get();c == ' ' || c == '\n';c = get()); if(it) it--; return c != EOF; } void put(char c){ if(it == LEN) fwrite(s,1,LEN,stdout), it = 0; s[it++] = c; } void flush(){ fwrite(s,1,it,stdout); } }buff,bufo; inline int getint(){ char c; int res = 0, sig = 1; for(c = buff.get();c < '0' || c > '9';c = buff.get()) if(c == '-') sig = -1; for(;c >= '0' && c <= '9';c = buff.get()) res = res * 10 + (c - '0'); return sig * res; } inline ll getll(){ char c; ll res = 0, sig = 1; for(c = buff.get();c < '0' || c > '9';c = buff.get()) if(c == '-') sig = -1; for(;c >= '0' && c <= '9';c = buff.get()) res = res * 10 + (c - '0'); return sig * res; } inline void putint(int x,char suf){ if(!x) bufo.put('0'); else{ if(x < 0) bufo.put('-'), x = -x; int k = 0; char s[15]; while(x){ s[++k] = x % 10 + '0'; x /= 10; } for(;k;k--) bufo.put(s[k]); } bufo.put(suf); } inline void putll(ll x,char suf){ if(!x) bufo.put('0'); else{ if(x < 0) bufo.put('-'), x = -x; int k = 0; char s[25]; while(x){ s[++k] = x % 10 + '0'; x /= 10; } for(;k;k--) bufo.put(s[k]); } bufo.put(suf); } inline char get_char(){ char c; for(c = buff.get();c == ' ' || c == '\n';c = buff.get()); return c; } #define maxn 200005 const double pi = acos(-1); struct Query{ int opt,x0,y0,x2,y2,v; // opt = 2: v = d // opt = 3: (x0,y0) = (x,y) // opt = 4: v = d }qs[maxn]; int id[maxn],num; int n,len; vector <double> thetas; struct Sgt{ int maxi[maxn << 3],add[maxn << 3]; void up(int id){ maxi[id] = max(maxi[id << 1],maxi[id << 1 | 1]); maxi[id] += add[id]; } void down(int id){ if(add[id]){ maxi[id << 1] += add[id]; add[id << 1] += add[id]; maxi[id << 1 | 1] += add[id]; add[id << 1 | 1] += add[id]; add[id] = 0; } } void _plus(int id,int l,int r,int ql,int qr,int x){ if(ql <= l && r <= qr){ maxi[id] += x; add[id] += x; }else{ down(id); int mid = (l + r) >> 1; if(ql <= mid) _plus(id << 1,l,mid,ql,qr,x); if(mid < qr) _plus(id << 1 | 1,mid + 1,r,ql,qr,x); up(id); } } int query(int id,int l,int r,int ql,int qr){ if(ql <= l && r <= qr) return maxi[id]; down(id); int mid = (l + r) >> 1, res = 0; if(ql <= mid) res = max(res,query(id << 1,l,mid,ql,qr)); if(mid < qr) res = max(res,query(id << 1 | 1,mid + 1,r,ql,qr)); return res; } }sgt; void range_add(double a,double b,int v){ if(a > b) swap(a,b); int id_a = lower_bound(thetas.begin(),thetas.end(),a) - thetas.begin() + 1, id_b = lower_bound(thetas.begin(),thetas.end(),b) - thetas.begin() + 1; if(b - a > pi){ sgt._plus(1,1,len,1,id_a,v); sgt._plus(1,1,len,id_b,len,v); }else{ sgt._plus(1,1,len,id_a,id_b,v); } } int query_max(double a,double b){ if(a > b) swap(a,b); int id_a = lower_bound(thetas.begin(),thetas.end(),a) - thetas.begin() + 1, id_b = lower_bound(thetas.begin(),thetas.end(),b) - thetas.begin() + 1; if(b - a > pi) return max(sgt.query(1,1,len,1,id_a),sgt.query(1,1,len,id_b,len)); return sgt.query(1,1,len,id_a,id_b); } int main(){ n = getint(); thetas.push_back(-pi); thetas.push_back(pi); for(int i = 1;i <= n;i++){ qs[i].opt = getint(); if(qs[i].opt == 1){ id[++num] = i; qs[i].x0 = getint(), qs[i].y0 = getint(), qs[i].x2 = getint(), qs[i].y2 = getint(), qs[i].v = getint(); thetas.push_back(atan2(qs[i].y0,qs[i].x0)), thetas.push_back(atan2(qs[i].y2,qs[i].x2)); }else if(qs[i].opt == 2){ qs[i].v = getint(); }else if(qs[i].opt == 3){ qs[i].x0 = getint(), qs[i].y0 = getint(); thetas.push_back(atan2(qs[i].y0,qs[i].x0)); }else{ qs[i].v = getint(); } } sort(thetas.begin(),thetas.end()); thetas.erase(unique(thetas.begin(),thetas.end()),thetas.end()); len = thetas.size(); for(int i = 1;i <= n;i++){ if(qs[i].opt == 1){ range_add(atan2(qs[i].y0,qs[i].x0),atan2(qs[i].y2,qs[i].x2),qs[i].v); }else if(qs[i].opt == 2){ int j = id[qs[i].v]; range_add(atan2(qs[j].y0,qs[j].x0),atan2(qs[j].y2,qs[j].x2),-qs[j].v); id[qs[i].v] = -1; }else if(qs[i].opt == 3){ printf("%d\n", query_max(atan2(qs[i].y0,qs[i].x0),atan2(qs[i].y0,qs[i].x0))); }else{ int j = id[qs[i].v]; if(j == -1) puts("oops!"); else{ printf("%d\n", query_max(atan2(qs[j].y0,qs[j].x0),atan2(qs[j].y2,qs[j].x2))); } } } return 0; } ``` RunID: [28847331](https://www.luogu.com.cn/record/28847331),跑的还挺快。。。