(复制一下题面好了~)

题目背景
小卡买到了一套新房子,他十分的高兴,在房间里转来转去。
题目描述
晚上,小卡从阳台望出去,“哇~~~~好多星星啊”,但他还没给其他房间设一个窗户,天真的小卡总是希望能够在晚上能看到最多最亮的星星,但是窗子的大小是固定的,边也必须和地面平行。这时小卡使用了超能力(透视术)知道了墙后面每个星星的位置和亮度,但是小卡发动超能力后就很疲劳,只好拜托你告诉他最多能够有总和多亮的星星能出现在窗口上。
输入输出格式
输入格式:
本题有多组数据,第一行为T 表示有T组数据T<=10
对于每组数据
第一行3个整数n,W,H,(n<=10000,1<=W,H<=1000000)表示有n颗星星,窗口宽为W,高为H。
接下来n行,每行三个整数xi,yi,li 表示星星的坐标在(xi,yi),亮度为li。(0<=xi,yi<2^31)
输出格式:
T个整数,表示每组数据中窗口星星亮度总和的最大值。
输入输出样例
说明
小卡买的窗户框是金属做的,所以在边框上的不算在内。
喜欢这个题目背景~
这类题目有一个很巧妙的转化,把移动的窗口(面)和星星(点)转成 可以覆盖到星星的(面)和窗口的左下角(点)
什么意思呢?(可以结合下面的图片理解)
把每一个星星作为右上角,在它的左下方划出一片窗口大小的区域,表示只要窗口的左下角落在这一片区域里就一定能覆盖到这颗星星。
那么不同星星的重叠部分就代表能同时覆盖这几颗星星了。
(下图中,只要窗口落在阴影部分,就能同时覆盖到三颗星星)

所以这一题的解法就是:
想象一条扫描线从左扫到右边,只要进入了星星的区域,扫描线上这段区间就可以取到这颗星星的值,等过了区域再减去这颗星星的值。
那就可以用线段树来做啦,每次挪动找出区间的最值更新答案就可以了。
看到题目最后的提示:小卡买的窗户框是金属做的,所以在边框上的不算在内。(惊!
边框居然不算,好吧那就只好把范围缩小,到了阴影部分外的那条平行y轴的线就可以把这颗星星的贡献减掉了。(用Windows XP 画的的图,有点丑)

还有,星星的坐标很大,记得离散化。
具体操作细节可以看代码(用了vector来维护坐标上加和减的星星)
(代码虽然很长,但结构还算清晰吧)
1 #include<iostream>
2 #include<cstdio>
3 #include<cstring>
4 #include<cstdlib>
5 #include<vector>
6 #include<algorithm>
7
8 #define For(i,a,b) for(int i=a;i<=b;++i)
9 #define Pn putchar('\n')
10 #define llg long long
11
12 using namespace std;
13
14 const int N=2e4+10;
15
16 struct LIS{
17 int x,y,id;
18 }Lis[N*2];
19
20 struct Star{
21 int x1,x2,y1,y2;
22 llg lgt;
23 Star(){
24 x1=0; x2=0; y1=0; y2=0;
25 lgt=0;
26 }
27 }st[N];
28
29 vector<int>ads[N];
30 vector<int>mns[N];
31
32 int tot=0,n,m,W,H,x,y;
33 llg tag[N*4],mx[N*4],ans=0;
34
35 void read(int &v){ //读入优化,和输出优化
36 v=0; bool fg=0;
37 char c=getchar(); if(c=='-')fg=1;
38 while(c<'0'||c>'9'){c=getchar(); if(c=='-')fg=1;}
39 while(c>='0'&&c<='9'){v=v*10+c-'0',c=getchar();if(c=='-')fg=1;}
40 if(fg)v=-v;
41 }
42 void read(llg &v){
43 v=0; bool fg=0;
44 char c=getchar(); if(c=='-')fg=1;
45 while(c<'0'||c>'9'){c=getchar(); if(c=='-')fg=1;}
46 while(c>='0'&&c<='9'){v=v*10+c-'0',c=getchar();if(c=='-')fg=1;}
47 if(fg)v=-v;
48 }
49 void write(int x){
50 if(x>9)write(x/10);
51 int xx=x%10;
52 putchar(xx+'0');
53 }
54 //排序
55 bool cmpX(const LIS &a,const LIS &b){
56 return a.x<b.x;
57 }
58 bool cmpY(const LIS &a,const LIS &b){
59 return a.y<b.y;
60 }
61 //线段树操作
62 void pDown(int o){
63 llg tg=tag[o]; tag[o]=0;
64 int ls=o<<1,rs=o<<1|1;
65 tag[ls]+=tg; tag[rs]+=tg;
66 mx[ls]+=tg; mx[rs]+=tg;
67 }
68 void Ins(int o,int l,int r,int lx,int rx,llg dt){
69 if(lx<=l&&rx>=r){
70 mx[o]+=dt; tag[o]+=dt;
71 return;
72 }
73 int m=(l+r)>>1;
74 int ls=o<<1,rs=o<<1|1;
75 if(tag[o])pDown(o);
76 if(lx<=m)Ins(ls,l,m,lx,rx,dt);
77 if(rx>m)Ins(rs,m+1,r,lx,rx,dt);
78 mx[o]=max(mx[ls],mx[rs]);
79 }
80
81 int main(){
82 int T; read(T);
83 while(T--){
84 tot=0; ans=0;
85 memset(tag,0,sizeof(tag));
86 memset(mx,0,sizeof(mx));
87
88 read(n); read(W); read(H);
89 For(i,1,n){ //存下星星区域的右上角和左下角
90 read(x); read(y); read(st[i].lgt);
91 st[i].x1=st[i].x2=st[i].y1=st[i].y2=0;
92 Lis[++tot].x=x;
93 Lis[tot].y=y,Lis[tot].id=i;
94
95 Lis[++tot].x=x+W-1;
96 Lis[tot].y=y-H+1,Lis[tot].id=i;
97 }
98 Lis[0].x=-2147483600;
99 Lis[0].y=-2147483600;
100
101 sort(Lis+1,Lis+tot+1,cmpY); //分别对X和Y离散化
102 int ty=0;
103 For(i,1,tot){
104 if(Lis[i].y!=Lis[i-1].y)ty++;
105 int ID=Lis[i].id;
106 if(!st[ID].y2){
107 st[ID].y2=ty;
108 }else{
109 st[ID].y1=ty;
110 }
111 }
112
113 sort(Lis+1,Lis+tot+1,cmpX);
114 int tx=0;
115 For(i,1,tot){
116 if(Lis[i].x!=Lis[i-1].x)tx++;
117 int ID=Lis[i].id;
118 if(!st[ID].x1){
119 st[ID].x1=tx;
120 }else{
121 st[ID].x2=tx;
122 }
123 }
124
125 For(i,1,tx+1){ //初始化vector
126 ads[i].clear();
127 mns[i].clear();
128 }
129
130 For(i,1,n){
131 int lx,rx; //把星星挂到相应的横坐标上
132 lx=st[i].x1; //ads为加, mns为减
133 rx=st[i].x2+1;
134 ads[lx].push_back(i);
135 mns[rx].push_back(i);
136 }
137 For(i,1,tx){
138 int sz;
139
140 sz=mns[i].size();
141 For(j,0,sz-1){ //先减后加
142 int ID=mns[i][j];
143 int lx,rx;
144 lx=st[ID].y2;
145 rx=st[ID].y1;
146 Ins(1,1,ty,lx,rx,-st[ID].lgt);
147
148 }
149
150 sz=ads[i].size();
151 For(j,0,sz-1){
152 int ID=ads[i][j];
153 int lx,rx;
154 lx=st[ID].y2;
155 rx=st[ID].y1;
156 Ins(1,1,ty,lx,rx,st[ID].lgt);
157 }
158 ans=max(ans,mx[1]);
159 }
160 write(ans); Pn;
161 }
162 return 0;
163 }
来源:https://www.cnblogs.com/HLAUV/p/9931979.html