陰影映射(線段樹)

實時陰影是電子游戲中最為重要的畫面效果之一。在計算機圖形學中,通常使用陰影映射方法來實現實時陰影。

游戲開發部正在開發一款 2D 游戲,同時希望能夠在 2D 游戲中模仿 3D 游戲的光影效果,請幫幫游戲開發部!

給定 x-y 平面上的 n 個矩形,矩形的邊界平行于坐標軸,且可能相互重疊。同時給定點光源的坐標。現有 m 次操作,每次操作添加或刪除一個矩形,或詢問 x 軸上的一點是否在陰影內。

輸入格式

第一行,兩個整數 n , m n,m n,m( 1 ≤ n , m ≤ 2 × 1 0 5 1≤n,m≤2×10^5 1n,m2×105)。
第二行,兩個整數 l x , l y l_x,l_y lx?,ly?,表示光源的坐標為 ( l x , l y ) (l_x,l_y) (lx?,ly?) ∣ l x ∣ ≤ 2 × 1 0 5 , 0 < l y ≤ 2 × 1 0 5 |l_x|≤2×10^5,0<l_y≤2×10^5 lx?2×105,0<ly?2×105
接下來 n n n 行,每行 5 個整數 i d , x , y , w , h id,x,y,w,? id,x,y,w,h,表示編號為 i d id id 的矩形,左下角坐標為 ( x , y ) (x,y) (x,y),寬為 w w w,高為 h ? h
接下來 m m m 行,每行先輸入一個正整數 o p t opt opt∈[1,3]。

  • o p t = 1 opt=1 opt=1,則接下來輸入 5 個整數 i d , x , y , w , h id,x,y,w,? id,x,y,w,h,表示增加一個編號為 i d id id,且左下角坐標為 ( x , y ) (x,y) (x,y),寬和高為 w w w h ? h 的矩形。
  • o p t = 2 opt=2 opt=2,則接下來輸入一個整數 i d id id,表示刪除編號為 i d id id 的矩形。
  • o p t = 3 opt=3 opt=3,則接下來輸入一個整數 p p p,表示查詢坐標 ( p , 0 ) (p,0) (p,0) 是否在陰影中。

1 ≤ i d ≤ 4 × 1 0 5 1≤id≤4×10^5 1id4×105
∣ x ∣ ≤ 2 × 1 0 5 , 0 < y ≤ 2 × 1 0 5 |x|≤2×10^5,0<y≤2×10^5 x2×105,0<y2×105
0 < w , h ≤ 2 × 1 0 5 0<w,?≤2×10^5 0<w,h2×105
∣ p ∣ ≤ 1 0 9 |p|≤10^9 p109
保證任意時刻場景中所有矩形的 i d id id 互不相同。保證所有矩形各個頂點的 y y y 坐標一定嚴格小于光源的 y y y坐標。若詢問點在陰影的邊界上,仍算作在陰影內。

輸出格式

對于每個 o p t = 3 opt=3 opt=3 的詢問,若詢問的點在陰影中,則輸出一行 YES,否則輸出一行 NO

樣例

input
3 19
4 7
1 1 1 2 1
2 6 1 2 3
3 5 2 4 1
3 -1
3 0
3 2
3 3
3 4
3 5
3 6
3 12
3 13
3 14
1 4 4 5 2 1
3 3
3 4
3 5
3 18
3 19
2 1
3 2
3 3
output
NO
YES
YES
NO
NO
NO
YES
YES
YES
NO
NO
YES
YES
YES
NO
NO
NO

提示

在進行所有修改操作之前,所有矩形的位置如下 (綠色部分為陰影區域):
002.png
在加入一個矩形后,所有矩形的位置如下:
003.png
在刪除一個矩形后,所有矩形的位置如下:
004.png

很容易想到利用線段樹維護陰影區間,添加陰影即為在[l,r]范圍內進行+1操作,刪除陰影為-1

但是本題的數據范圍過大,特別注意當光源與矩形非常接近時,光線幾乎平行于x軸,這時用long long都會存在爆精度問題

所以必須進行離散化

我們可以發現需要用到的坐標是有限的,最多不超過 2 × n + m 2×n+m 2×n+m個坐標點,用到的坐標點為線段端點(l,r)和查詢位置p

AC代碼如下

注意這題的時間復雜度卡的很死,需要采用IO加速,同時切忌使用STL容器

#include <iostream>
#include <algorithm>
#include <map>
#include <cmath>
using namespace std;
#define int long long
const int max_n = 5e5 + 50;
const int max_m = 5e5 + 50;
const int max_len = 1e6 + 50;
const double eps = 1e-8;typedef struct {int idx, x1, y1, x2, y2;
}node;typedef struct {int opt[6];
}query;typedef struct {double first, second;
}line;int n, m;
node arr[max_n];
query qarr[max_m];
int tmpidx, lineidx;
double tmparr[max_len];
line lines[max_n + max_m];
map<double, int>dict;
int tree[max_len];inline int read() {int x = 0, y = 1; char c = getchar();while (c < '0' || c > '9') {if (c == '-') y = -1;c = getchar();}while (c >= '0' && c <= '9') {x = x * 10 + c - '0';c = getchar();}return x * y;
}inline int lowbit(int x) {return x & -x;
}int ask(int p) {int res = 0;for (int i = p; i > 0; i -= lowbit(i)) {res += tree[i];}return res;
}void add(int p, int x) {for (int i = p; i < max_len; i += lowbit(i)) {tree[i] += x;}
}double project(int x, int y) {if (x == arr[0].x1) return x;double k = double(y - arr[0].y1) / double(x - arr[0].x1);double b = k * x - y;return b / k;
}void process(node n) {double l, r, ret;l = r = project(n.x1, n.y1);ret = project(n.x1, n.y2);l = min(l, ret); r = max(r, ret);ret = project(n.x2, n.y1);l = min(l, ret); r = max(r, ret);ret = project(n.x2, n.y2);l = min(l, ret); r = max(r, ret);tmparr[tmpidx++] = l;tmparr[tmpidx++] = r;lines[lineidx++] = line{ l,r };
}inline bool equal(double x, double y) {return fabs(x - y) < eps;
}void discrete() {sort(tmparr, tmparr + tmpidx);int cnt = 0;for (int i = 0; i < tmpidx; i++) {if (i == 0) {dict[tmparr[i]] = ++cnt;continue;}if (tmparr[i] != tmparr[i - 1])dict[tmparr[i]] = ++cnt;}
}signed main() {n = read(); m = read();arr[0].x1 = read();arr[0].y1 = read();int tmpid;int cnt;tmpidx = lineidx = 0;for (cnt = 1; cnt <= n; cnt++) {tmpid = read();arr[tmpid].x1 = read();arr[tmpid].y1 = read();arr[tmpid].x2 = arr[tmpid].x1 + read();arr[tmpid].y2 = arr[tmpid].y1 + read();arr[tmpid].idx = cnt - 1;process(arr[tmpid]);}int optnum;for (int i = 1; i <= m; i++) {qarr[i].opt[0] = read();switch (qarr[i].opt[0]){case 1:tmpid = read();arr[tmpid].x1 = read();arr[tmpid].y1 = read();arr[tmpid].x2 = arr[tmpid].x1 + read();arr[tmpid].y2 = arr[tmpid].y1 + read();arr[tmpid].idx = cnt++ - 1;process(arr[tmpid]);qarr[i].opt[1] = tmpid;break;case 2:qarr[i].opt[1] = read();break;case 3:qarr[i].opt[1] = read();tmparr[tmpidx++] = qarr[i].opt[1];break;default:break;}}discrete();for (int i = 0; i < n; i++) {double l = lines[i].first;double r = lines[i].second;l = dict[l]; r = dict[r];add(l, 1);add(r + 1, -1);}for (int i = 1; i <= m; i++) {if (qarr[i].opt[0] == 1) {int p = qarr[i].opt[1];p = arr[p].idx;double l = lines[p].first;double r = lines[p].second;l = dict[l]; r = dict[r];add(l, 1);add(r + 1, -1);}else if (qarr[i].opt[0] == 2) {int p = qarr[i].opt[1];p = arr[p].idx;double l = lines[p].first;double r = lines[p].second;add(dict[l], -1);add(dict[r] + 1, 1);}else {double p = qarr[i].opt[1];if (ask(dict[p])) { printf("YES\n");}else printf("NO\n");}}return 0;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/14556.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/14556.shtml
英文地址,請注明出處:http://en.pswp.cn/web/14556.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

再次學習History.scrollRestoration

再次學習History.scrollRestoration 之前在react.dev的源代碼中了解到了這個HIstory的屬性&#xff0c;當時寫了一篇筆記來記錄我對它的理解&#xff0c;現在看來還是一知半解。所以今天打算重新學習一下這個屬性&#xff0c;主要從屬性以及所屬對象的介紹、使用方法&#xff0…

每日一題(2)——100~200間的素數

方法一&#xff1a; public class suCount {public static void main(String[] args){int sum0;c1:for(int i100;i<200;i){for(int j2;j<i;j){if(i%j0)continue c1;//continue中斷循環&#xff0c;且返回外層循環&#xff0c;進入下一次遍歷else if(ji-1){System.out.pr…

Linux信號:信號的保存

目錄 一、信號在內核中的表示 二、sigset_t 2.1sigset_t的概念和意義 2.2信號集操作數 三、信號集操作數的使用 3.1sigprocmask 3.2sigpending 3.3sigemptyset 四、代碼演示 一、信號在內核中的表示 實際執行信號的處理動作稱為信號 遞達(Delivery) 。 信號從產生到遞達…

Mysql數據庫——DML操作

目錄 添加數據&#xff08;INSERT&#xff09; 修改數據&#xff08;UPDATE&#xff09; 刪除數據&#xff08;DELETE&#xff09; 添加數據&#xff1a; &#xff08;1). 給指定字段添加數據 &#xff08;2). 給全部字段添加數據 &#xff08;3). 批量添加數據 修改數據: 案例…

【STM32】HAL庫點燈

【STM32】HAL庫點燈 一、探究目標二、探究原理2.1 ST開發庫2.1.1 直接配置寄存器2.1.2 標準外設庫2.1.3 HAL庫2.2 HAL開發2.2.1 環境配置2.2.2 時鐘配置2.2.3 GPIO配置2.2.4 工程創建2.2.5 KEIL代碼![在這里插入圖片描述](https://img-blog.csdnimg.cn/direct/bf1c95d5c6724a6a…

NextGen Mirth Connect XStream反序列化遠程代碼執行漏洞(CVE-2023-43208)

0x01 產品簡介 NextGen Mirth Connect是是美國NextGen公司的一個醫療集成引擎,主要用于醫療領域的系統集成和數據交換,支持多種協議和標準。 0x02 漏洞概述 NextGen Mirth Connect 4.4.1之前版本存在遠程代碼執行漏洞,未經身份認證的攻擊者可利用該漏洞遠程執行代碼。 0…

混合組網VS傳統網絡:智能硬件混合組網優劣勢淺要解析

智能硬件混合組網是一種利用多種通信技術相結合的方法&#xff0c;以實現更靈活、更可靠的網絡連接。通過藍牙、Wi-Fi、LoRa、4G相互之間的不同通訊方式&#xff0c;根據應用場景的不同以及現場實際環境&#xff0c;優選最佳物聯網混合組網方案&#xff0c;以達到部署最便捷性價…

一張SSL證書如何同時保護多個域名及其子域名?

在互聯網時代&#xff0c;數據安全和隱私保護變得至關重要&#xff0c;而SSL證書作為確保網站安全的重要工具&#xff0c;其重要性不言而喻。本文將詳細探討一種特殊的SSL證書——多域名通配符SSL證書&#xff0c;它為網站管理員提供了一種高效、經濟的方式來保護多個域名及其子…

學Java以及IDEA工具中遇到的常用單詞

Arithmetic 算術 operator 運算符 relational 關系 logic 邏輯 assign 分配 TernaryOperator 三元運算符、 gender 性別 lebal 標簽 array 數組 two dimesional 二維 object 對象 method 方法 row 行 column 列 parameter 參數 recursion 遞歸 overload 方法重載 calculate 計算…

MyBatis從入門到“入土“

&#x1f495;喜歡的朋友可以關注一下&#xff0c;下次更新不迷路&#xff01;&#x1f495;(●?●) 目錄 一、Mybatis為何物&#xff1f;&#x1f44c; 二、快速入門&#x1f923; 1、新建項目&#x1f60a; 2、數據庫建表&#x1f60a; 3、導入依賴的jar包&#x1f60a;…

Linux學習筆記6

TFTP 服務器搭建和測試 關于TFTP:TFTP&#xff08;Trivial File Transfer Protocol&#xff0c;簡單文件傳輸協議&#xff09;&#xff0c;是一個基于UDP 協議實現 的用于在客戶機和服務器之間進行簡單文件傳輸的協議&#xff0c;適合于開銷不大、不復雜的應用場合 搭建服務器…

后量子密碼的發展和應用

后量子算法&#xff0c;特別是后量子密碼(PQC)&#xff0c;是近年來密碼學領域的一個熱門話題。隨著量子計算技術的快速發展&#xff0c;傳統的公鑰密碼算法面臨著被量子計算機破解的威脅。為了應對這一挑戰&#xff0c;后量子密碼應運而生&#xff0c;成為了一種能夠抵抗量子計…

【論文筆記】| 蛋白質大模型ProLLaMA

【論文筆記】| 蛋白質大模型ProLLaMA ProLLaMA: A Protein Large Language Model for Multi-Task Protein Language Processing Peking University Theme: Domain Specific LLM Main work&#xff1a; 當前 ProLLM 的固有局限性&#xff1a;&#xff08;i&#xff09;缺乏自然…

Redis篇 在linux系統上安裝Redis

安裝Redis 在Ubuntu上安裝Redis 在Ubuntu上安裝Redis 在linux系統中,我們安裝Redis,必須先使它有root權限. 那么在linux中,如何切換到root用戶權限呢? sudo su 就可切換到用戶權限了. 在切換到用戶權限后,我們需要用一條命令來搜索Redis相關的軟件包 apt search redis 會出現非…

ROS2學習——節點話題通信(2)

目錄 一、ROS2節點 1.概念 2.實例 &#xff08;1&#xff09;ros2 run &#xff08;2&#xff09;ros2 node list &#xff08;3&#xff09;remapping重映射 &#xff08;4&#xff09;ros2 node info 二、話題 &#xff08;1&#xff09; ros2 topic list &#xf…

頭歌openGauss-存儲過程第1關:創建存儲過程

編程要求 1、創建第1個存儲過程&#xff0c;并調用&#xff1b; 1&#xff09;創建存儲過程&#xff0c;查詢emp表數據&#xff1b; 2&#xff09;調用存儲過程&#xff1b; --創建存儲過程&#xff0c;獲得計算機&#xff08;cs&#xff09;系學生選課情況并將結果寫入臨時表t…

人臉識別:基于卷積神經網絡(CNN)分類思想的人臉識別系統

本文來自公眾號 “AI大道理” —————— 項目配套視頻課程&#xff1a; 平臺&#xff1a;荔枝微課 鏈接&#xff1a;十方教育 項目地址&#xff1a;https://github.com/AIBigTruth/CNN_faces_recognition 之前很多人來詢問這個項目怎么做&#xff0c;代碼跑不起來&#…

數據庫讀寫分離

實現 MySQL 的讀寫分離主要可以通過以下幾種方式&#xff1a; 一主多從架構&#xff1a; 設置一個主數據庫&#xff08;Master&#xff09;來處理寫操作&#xff08;如 INSERT、UPDATE、DELETE&#xff09;。 設置多個從數據庫&#xff08;Slave&#xff09;來處理讀操作&…

USB數據恢復軟件:輕松找回U盤重要數據!

USB數據丟失的原因 USB數據丟失有一些常見原因&#xff0c;了解這些原因有利于恢復數據。 文件意外刪除病毒攻擊軟件錯誤未安全彈出USB設備格式化USB設備 順便一提&#xff0c;如果你通過快捷鍵“Ctrl D”刪除了數據&#xff0c;那你可以從回收站中還原它們。如果你永久刪除…

Isaac Sim仿真平臺學習(1)認識Isaac Sim

0.前言 上一個教程中我們下載好了Isaac Sim&#xff0c;這一章我們將來簡單了解一下Isaac Sim平臺。 isaac Sim仿真平臺安裝-CSDN博客 1.Isaac Sim是啥&#xff1f; What Is Isaac Sim? — Omniverse IsaacSim latest documentation Isaac Sim是NVDIA Omniverse平臺的機器…