zoukankan      html  css  js  c++  java
  • 【Luogu P1502】 窗口的星星

    →传送窗口

    (复制一下题面好了~)

    题目背景

    小卡买到了一套新房子,他十分的高兴,在房间里转来转去。

    题目描述

    晚上,小卡从阳台望出去,“哇~~~~好多星星啊”,但他还没给其他房间设一个窗户,天真的小卡总是希望能够在晚上能看到最多最亮的星星,但是窗子的大小是固定的,边也必须和地面平行。这时小卡使用了超能力(透视术)知道了墙后面每个星星的位置和亮度,但是小卡发动超能力后就很疲劳,只好拜托你告诉他最多能够有总和多亮的星星能出现在窗口上。

    输入输出格式

    输入格式:

    本题有多组数据,第一行为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个整数,表示每组数据中窗口星星亮度总和的最大值。

    输入输出样例

    输入样例#1: 
    2
    3 5 4
    1 2 3
    2 3 2
    6 3 1
    3 5 4
    1 2 3
    2 3 2
    5 3 1
    
    输出样例#1: 
    5
    6
    

    说明

    小卡买的窗户框是金属做的,所以在边框上的不算在内。


    喜欢这个题目背景~

    这类题目有一个很巧妙的转化,把移动的窗口(面)和星星(点)转成 可以覆盖到星星的(面)和窗口的左下角(点)

    什么意思呢?(可以结合下面的图片理解)

    把每一个星星作为右上角,在它的左下方划出一片窗口大小的区域,表示只要窗口的左下角落在这一片区域里就一定能覆盖到这颗星星。

    那么不同星星的重叠部分就代表能同时覆盖这几颗星星了。

    (下图中,只要窗口落在阴影部分,就能同时覆盖到三颗星星) 

    所以这一题的解法就是:

    想象一条扫描线从左扫到右边,只要进入了星星的区域,扫描线上这段区间就可以取到这颗星星的值,等过了区域再减去这颗星星的值。

    那就可以用线段树来做啦,每次挪动找出区间的最值更新答案就可以了。

    看到题目最后的提示:小卡买的窗户框是金属做的,所以在边框上的不算在内。(惊!

    边框居然不算,好吧那就只好把范围缩小,到了阴影部分外的那条平行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('
    ')
     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 }
  • 相关阅读:
    2021.6.7
    2021.6.4
    2021.6.3
    2021.6.2 团队第二阶段冲刺第十天
    2021.6.1 团队第二阶段冲刺第九天
    2021.5.31 团队第二阶段冲刺第八天
    2021.5.30 团队第二阶段冲刺第七天
    逻辑卷的使用
    磁盘阵列
    磁盘配额
  • 原文地址:https://www.cnblogs.com/HLAUV/p/9931979.html
Copyright © 2011-2022 走看看