luogu P1502 窗口的星星

题目链接

P1502 窗口的星星

题解

扫描线+线段树
线段树的每一个节点处理的是左边框放在当前x-1位置时的框内星星的亮度大小
按照x坐标进行离散化,得到离散化后每一个坐标x的可影响的范围
维护扫描线,扫到可以加某颗星星就把星星加进去,扫到该出来的时候就把星星搞出来,线段树维护一下

代码

#include<cstdio>
#include<cstring>
#include<algorithm>

const int maxn = 100007; 

int n,w,h;
int pou[maxn << 2],T[maxn << 2],tag[maxn << 2]; 

struct P {
    int x,y,l,k,ymax,id;
}star[maxn << 2];
inline bool cmp1(P a,P b) { return a.y < b.y; }
inline bool cmp2(P a,P b) { if(a.id == b.id) return a.k < b.k; return a.id < b.id; }
inline bool cmp3(P a,P b) { if(a.x == b.x) return a.k < b.k; return a.x < b.x;  }
void pushdown(int x,int l,int r) {
    if(!tag[x]) return;
    if(l == r) { tag[x] = 0; return; }
    int mid = l + r >> 1;
    tag[x << 1] += tag[x]; tag[x << 1 | 1] += tag[x];
    T[x << 1] += tag[x];  T[x << 1 | 1]+=tag[x];
    tag[x] = 0;
} 

void modify(int x,int l,int r,int tl,int tr,int val){
    pushdown(x,l,r);
    if(tl <= l && r <= tr) {
        tag[x] = val; T[x] += val;
        return;
    }
    int mid = (l + r) >> 1;
    if(tl <= mid) modify(x << 1,l,mid,tl,tr,val);
    if(mid < tr) modify(x << 1 | 1,mid + 1,r,tl,tr,val);
    T[x] = std::max(T[x << 1],T[x << 1 | 1]);
}
void init() {
    memset(T,0,sizeof(T));
    memset(tag,0,sizeof(tag));
    scanf("%d%d%d",&n,&w,&h);
    for(int x,y,l,i = 1;i <= n ;++ i) {
        scanf("%d%d%d",&x,&y,&l);
        star[i] = (P) {x, y, l, 1};
        star[i + n] = (P){ x + w - 1, y, -l, 2};
        star[i + (n << 1)].y = y + h - 1;
        star[i + (n << 1)].k = 3;
        star[i].id = star[i + n].id = star[i + (n << 1)].id = i;
    }
}  

void solve() {
    std::sort(star + 1,star + n * 3 + 1,cmp1);
    int cnt = 0;
    for(int i = 1;i <= n * 3;++ i) pou[i] = star[i].y;
    for(int i = 1;i <= n * 3;++ i)
        if(star[i].y == pou[i - 1]) star[i].y = star[i - 1].y;
            else star[i].y =++ cnt;
    std::sort(star + 1,star + n * 3 + 1,cmp2);
    for(int i = 1;i <= n * 3;i += 3) star[i].ymax = star[i + 1].ymax = star[i + 2].y;
    for(int i = 3;i <= n << 1;++ i)  star[i] = star[i + ((i - 1) >> 1)];
    std::sort(star + 1,star + (n << 1) + 1,cmp3);
    int ans = 0;
    for(int i = 1;i <= n << 1;++ i) {
        modify(1,0,cnt,star[i].y,star[i].ymax,star[i].l);
        ans = std::max(ans,T[1]);
    }
    printf("%d\n",ans);
    return ;
}
int main() {
    int t; scanf("%d",&t);
    while(t --) {
        init();
        solve();
    }
    return 0;
} 

原文地址:https://www.cnblogs.com/sssy/p/9461928.html

时间: 2024-08-03 11:04:31

luogu P1502 窗口的星星的相关文章

P1502 窗口的星星(扫描线入门第一题)

题目链接:https://www.luogu.org/problem/P1502 P1502 窗口的星星 提交2.78k 通过682 时间限制1.00s 内存限制125.00MB 提交代码加入收藏 题目提供者cyrcyr 难度省选/NOI- 历史分数100 提交记录查看题解 标签 高性能高级数据结构 查看算法标签 相关讨论 进入讨论版 查看讨论 推荐题目 查看推荐 展开 题目背景 小卡买到了一套新房子,他十分的高兴,在房间里转来转去. 题目描述 晚上,小卡从阳台望出去,“哇~~~~好多星星啊”,

Java窗口--漫天星星

学习Java过程中,在树上遇到的一个例子,我将这个例子“进化”了.具体向下看: 编写工具:EditPlus JDK版本: 1.7.0_60-b19 要求:输出 300 颗位置随机的星星 效果如下: 我认为花星星并不需要太过于复杂的绘制 大婶们,见了别笑小弟自恋哦~~~~ 思路: 1 . 创建一个 1024 x 768 的窗口 2 . 将画布添加到窗口上 (在窗口的重绘方法中花 300 颗星星) 3 . 显示窗口 1 import java.awt.*; //导入包涵窗口的类 2 3 public

【Luogu P1502】 窗口的星星

→传送窗口 (复制一下题面好了~) 题目背景 小卡买到了一套新房子,他十分的高兴,在房间里转来转去. 题目描述 晚上,小卡从阳台望出去,“哇~~~~好多星星啊”,但他还没给其他房间设一个窗户,天真的小卡总是希望能够在晚上能看到最多最亮的星星,但是窗子的大小是固定的,边也必须和地面平行.这时小卡使用了超能力(透视术)知道了墙后面每个星星的位置和亮度,但是小卡发动超能力后就很疲劳,只好拜托你告诉他最多能够有总和多亮的星星能出现在窗口上. 输入输出格式 输入格式: 本题有多组数据,第一行为T 表示有T

Luogu1502 窗口的星星 (线段树扫描线)

将每个点拓展为矩形,将\(y\)离散,延\(x\)轴扫描,每次更新最值 用了一百年的pushdown操作疑似有问题,WA了一发,y数组没开够又RE了一发... 话说POJ上的情书让我回忆起童年那个彪悍的女孩,一晃十年了 Fleeting time does not blur my memory of you. Can it really be 4 years since I first saw you? I still remember, vividly, on the beautiful Zh

数据结构(下)

1.树套树 (1)树状数组套树状数组 前置: 树状数组如何支持区间加以及区间查询 维护一个差分数组,用来求一个位置的值,我们只需要把前缀和看作是一个矩形, 减去两数插值产生的贡献即可 1.P4514 上帝造题的七分钟 题意:支持矩形加某个数和矩形查询值. 考虑将每个点差分,当我们要将\((a,b),(x,y)\)范围内的矩阵加1时,其实就是: \(A(a,b)+1\) \(A(x,b+1)-1\) \(A(a,y+1)-1\) \(A(x+1,y+1)+1\) 于是乎,前缀和: \[\sum_{

luogu题解 UVA11536 【Smallest Sub-Array】最短set区间&amp;滑动窗口

题目链接: https://www.luogu.org/problemnew/show/UVA11536 题目大意: 给定一个\(N,M,K\),构造这样的数列: \(x[1]=1,x[2]=2,x[3]=3\) \(x[i]=(x[i-1]+x[i-2]+x[i-3])\mod M+1(N>=i>=4)\) 然后问你是否存在一个在\(x[1]\)到\(x[n]\)中的区间,使得\([1,K]\)所有元素在其中至少出现过一次. 若存在,输出这个区间最短长度:否则输出\("sequen

luogu P1886滑动窗口

\(luogu\ P1886\)滑动窗口 题目链接 这道题目比较简单,但是因为经常忘记单调队列做滑动窗口所以写博客来加深一下印象. 如果求区间最小值,我们用发现右端点从前往后扫的方法一个数如果有贡献,当且仅当当前扫描的右端点的前面到这个数中间没有比这个数更小的数,因为如果有比这个数更小的数的话,这个更小的数肯定就会成为区间的最小值.如果一个数没有贡献的时候就是区间的左端点比这个数的下标要大的时候. 所以我们用一个双端队列来维护,每次进入队列的时候检查队尾的数如果比要加入得数大的话,就不断弹出队尾

luogu P1886 滑动窗口

题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值. 例如: The array is [1 3 -1 -3 5 3 6 7], and k = 3. 输入输出格式 输入格式: 输入一共有两行,第一行为n,k. 第二行为n个数(<INT_MAX). 输出格式: 输出共两行,第一行为每次窗口滑动的最小值 第二行为每次窗口滑动的最大值 输入输出样例 输入样例#1: 8 3 1 3 -1 -

滑动窗口(luogu 1886)

题目描述 现在有一堆数字共N个数字(N<=10^6),以及一个大小为k的窗口.现在这个从左边开始向右滑动,每次滑动一个单位,求出每次滑动后窗口中的最大值和最小值. 例如: The array is [1 3 -1 -3 5 3 6 7], and k = 3. 输入输出格式 输入格式: 输入一共有两行,第一行为n,k. 第二行为n个数(<INT_MAX). 输出格式: 输出共两行,第一行为每次窗口滑动的最小值 第二行为每次窗口滑动的最大值 输入输出样例 输入样例 8 3 1 3 -1 -3 5