結果
| 問題 |
No.2885 Range Triangle Collision Decision Queries
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2025-04-17 17:05:21 |
| 言語 | C++23 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
WA
|
| 実行時間 | - |
| コード長 | 6,158 bytes |
| コンパイル時間 | 3,920 ms |
| コンパイル使用メモリ | 291,840 KB |
| 実行使用メモリ | 249,692 KB |
| 最終ジャッジ日時 | 2025-04-17 17:07:22 |
| 合計ジャッジ時間 | 105,216 ms |
|
ジャッジサーバーID (参考情報) |
judge1 / judge5 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| sample | AC * 2 |
| other | AC * 42 WA * 11 |
ソースコード
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll INF = (1LL<<62);
// --- セグ木 for max / min over E_i, F_i ---
template<class T, class Op>
struct SegTree {
int n;
vector<T> st;
Op op; T e;
SegTree(int _n, T _e, Op _op):n(_n),e(_e),op(_op){
st.assign(4*n, e);
}
void build(int p,int l,int r,const vector<T>&A){
if(l==r){ st[p]=A[l]; return; }
int m=(l+r)>>1;
build(p<<1,l,m,A); build(p<<1|1,m+1,r,A);
st[p]=op(st[p<<1],st[p<<1|1]);
}
T query(int p,int l,int r,int i,int j){
if(i>r||j<l) return e;
if(i<=l&&r<=j) return st[p];
int m=(l+r)>>1;
return op(query(p<<1,l,m,i,j), query(p<<1|1,m+1,r,i,j));
}
// wrapper
void build(const vector<T>&A){ build(1,0,n-1,A); }
T query(int l,int r){ return query(1,0,n-1,l,r); }
};
// --- Merge‑sort tree: q→min p ---
struct Merge_qp {
int n;
vector<vector<ll>> Q; // 各ノードの q_k の昇順リスト
vector<vector<ll>> prefP; // 同長さで,prefix-min of p_k
Merge_qp(int _n):n(_n){
Q.resize(4*n);
prefP.resize(4*n);
}
void build(int p,int l,int r,
const vector<ll>& q, const vector<ll>& pval){
if(l==r){
Q[p]={q[l]};
prefP[p]={pval[l]};
return;
}
int m=(l+r)>>1;
build(p<<1,l,m,q,pval);
build(p<<1|1,m+1,r,q,pval);
// マージ
auto &Lq=Q[p<<1], &Rq=Q[p<<1|1];
auto &Lp=prefP[p<<1], &Rp=prefP[p<<1|1];
int sz=Lq.size()+Rq.size();
Q[p].resize(sz);
prefP[p].resize(sz);
merge(Lq.begin(),Lq.end(),Rq.begin(),Rq.end(),Q[p].begin());
// prefix-min を作るために,対応する p_k も併せてマージしつつ min を取る
int i=0,j=0,k=0;
ll curMin = INF;
while(i<(int)Lq.size()||j<(int)Rq.size()){
if(j==(int)Rq.size() || (i<(int)Lq.size() && Lq[i] <= Rq[j])){
curMin = min(curMin, Lp[i]);
++i;
} else {
curMin = min(curMin, Rp[j]);
++j;
}
prefP[p][k++] = curMin;
}
}
// 区間 [ql, qr] で q_k < qS の最小 p を返す
ll query_sub(int p,int l,int r,int i,int j,ll qS){
if(i>r||j<l) return INF;
if(i<=l&&r<=j){
// このノード内で q_k<qS の最小 prefix を二分探索
int pos = lower_bound(Q[p].begin(), Q[p].end(), qS) - Q[p].begin();
if(pos==0) return INF;
return prefP[p][pos-1];
}
int m=(l+r)>>1;
return min(
query_sub(p<<1,l,m,i,j,qS),
query_sub(p<<1|1,m+1,r,i,j,qS)
);
}
ll query(int L,int R,ll qS){
return query_sub(1,0,n-1,L,R,qS);
}
};
// --- Merge‑sort tree: p→max q ---
struct Merge_pq {
int n;
vector<vector<ll>> P; // 各ノードの p_k の昇順リスト
vector<vector<ll>> suffQ; // suffix-max of q_k
Merge_pq(int _n):n(_n){
P.resize(4*n);
suffQ.resize(4*n);
}
void build(int p,int l,int r,
const vector<ll>& pval, const vector<ll>& q){
if(l==r){
P[p]={pval[l]};
suffQ[p]={q[l]};
return;
}
int m=(l+r)>>1;
build(p<<1,l,m,pval,q);
build(p<<1|1,m+1,r,pval,q);
auto &Lp=P[p<<1], &Rp=P[p<<1|1];
auto &Lq=suffQ[p<<1], &Rq=suffQ[p<<1|1];
int sz=Lp.size()+Rp.size();
P[p].resize(sz);
suffQ[p].resize(sz);
merge(Lp.begin(),Lp.end(),Rp.begin(),Rp.end(),P[p].begin());
// suffix-max をつくるため、マージ後に後ろから scan
// まず対応 q_k を合わせるため同様にマージ二度
vector<ll> allQ(sz);
int i=0,j=0,k=0;
while(i<(int)Lp.size()||j<(int)Rp.size()){
if(j==(int)Rp.size() ||
(i<(int)Lp.size() && Lp[i]<=Rp[j])){
allQ[k++] = Lq[i++];
} else {
allQ[k++] = Rq[j++];
}
}
ll curMax = -INF;
for(int t=sz-1;t>=0;--t){
curMax = max(curMax, allQ[t]);
suffQ[p][t] = curMax;
}
}
// 区間 [L,R] で p_k > pS の最大 q を返す
ll query_sub(int p,int l,int r,int i,int j,ll pS){
if(i>r||j<l) return -INF;
if(i<=l&&r<=j){
int pos = upper_bound(P[p].begin(), P[p].end(), pS)
- P[p].begin();
if(pos==(int)P[p].size()) return -INF;
return suffQ[p][pos];
}
int m=(l+r)>>1;
return max(
query_sub(p<<1,l,m,i,j,pS),
query_sub(p<<1|1,m+1,r,i,j,pS)
);
}
ll query(int L,int R,ll pS){
return query_sub(1,0,n-1,L,R,pS);
}
};
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N; cin>>N;
vector<ll>A(N),B(N),D(N),E(N),F(N),p(N),q(N);
for(int i=0;i<N;i++){
cin>>A[i]>>B[i]>>D[i];
E[i]=B[i]-D[i];
F[i]=B[i];
p[i]=A[i]+B[i];
q[i]=A[i]-B[i];
}
// 1) build ST1,ST2
SegTree<ll,function<ll(ll,ll)>> stE(N, -INF,
[](ll a,ll b){return max(a,b);} );
SegTree<ll,function<ll(ll,ll)>> stF(N, +INF,
[](ll a,ll b){return min(a,b);} );
stE.build(E);
stF.build(F);
// 2) build merge‑sort trees
Merge_qp ms_qp(N);
ms_qp.build(1,0,N-1,q,p);
Merge_pq ms_pq(N);
ms_pq.build(1,0,N-1,p,q);
int Q; cin>>Q;
while(Q--){
int S,L,R;
cin>>S>>L>>R;
--S; --L; --R;
ll AS=A[S], BS=B[S], DS=D[S];
ll pS=p[S], qS=q[S];
// V1,V2
bool ok1 = (stE.query(L,R) < BS);
bool ok2 = (stF.query(L,R) > BS - DS);
// H1: q_k < qS の範囲 min p_k
ll m1 = ms_qp.query(L,R, qS);
bool ok3 = (m1 > pS - 2*DS);
// H2: p_k > pS の範囲 max q_k
ll m2 = ms_pq.query(L,R, pS);
bool ok4 = (m2 < qS + 2*DS);
cout << ((ok1&&ok2&&ok3&&ok4) ? "Yes\n" : "No\n");
}
return 0;
}