2020绵阳CCPC J-Joy of Handcraft

题意:给了n个灯泡,每个灯泡有自己的亮的时间长度和灯泡亮度。一段固定的时间是亮的,一段固定的时间是灭的,是一个周期性变化,问在1~m的时间中,每个时间内的最大亮度是多少。

写在前面
第一眼就是线段树
但是,当时没有具体去算有多少种区间,默认为由n^2个区间暴力区间赋值会T掉,这里奠定了这题GG的后果
所以立刻hack了正解做法。
然后后面我算了一下区间的个数只有mlogm个 并且这句话我跟队友重复说了好几遍了 能不能只处理区间端点 这样一定不会T。 可惜在一开始就把线段树做法否决了。后面也没去想线段树。

思路
其实这题是个水题,线段树板子题。
我们的思路其实反了,应该先去通过调和级数m/1+m/2+m/3…+m/m知道有mlogm个区间,然后才想到可以暴力区间赋值,而每次操作都是一个logn的复杂度,所以是可行的。
我们把线段的lazy用来标记每次的亮度,sum表示一个区间的最大亮度,sum和lazy去更新最值即可。
复杂度O(mlogmlogn)

#include<bits/stdc++.h>
using namespace std;
#define Max(a,b) (a<=b?b:a)
#define Min(a,b) (a>=b?b:a)
const int N=2e5+5;
struct Node{
    int t,x;
}a[N],b[N];
bool cmp(Node a,Node b){
    if(a.t==b.t) return a.x>b.x;
    return a.t<b.t;
}
inline int read() {
    int num=0, w=0;
    char ch=0;
    while (!isdigit(ch)) {
        w|=ch=='-';
        ch = getchar();
    }
    while (isdigit(ch)) {
        num = (num<<3) + (num<<1) + (ch^48);
        ch = getchar();
    }
    return w? -num: num;
}

struct node{
    int l,r;
    int sum,lazy;

}t[N<<2];
void build(int s,int l,int r){
    t[s].l=l,t[s].r=r,t[s].lazy=0;
    t[s].sum=0;
    if(l==r){
        return ;
    }
    int mid=l+r>>1;
    build(s<<1,l,mid);
    build(s<<1|1,mid+1,r);
}
void update(int s,int l,int r,int c){
    if(t[s].l==l && t[s].r==r){
        t[s].lazy=Max(t[s].lazy,c);
        t[s].sum=Max(t[s].sum,t[s].lazy);
        return ;
    }
    if(t[s].lazy){
        int Z=t[s].lazy;
        t[s].lazy=0;
        t[s<<1].lazy=Max(Z,t[s<<1].lazy);
        t[s<<1|1].lazy=Max(Z,t[s<<1|1].lazy);
    }
    int mid=t[s].l+t[s].r>>1;
    if(r<=mid){
        update(s<<1,l,r,c);
    }
    else{
        if(l>mid) update(s<<1|1,l,r,c);
        else {
            update(s<<1,l,mid,c);
            update(s<<1|1,mid+1,r,c);
        }
    }
    t[s].sum=Max(t[s<<1].sum,t[s<<1|1].sum);
}
int query(int s,int l,int r){
    if(t[s].l==l && t[s].r==r){
        t[s].sum=Max(t[s].sum,t[s].lazy);
        return t[s].sum;
    }
     if(t[s].lazy){
        int Z=t[s].lazy;
        t[s].lazy=0;
        t[s<<1].lazy=Max(Z,t[s<<1].lazy);
        t[s<<1|1].lazy=Max(Z,t[s<<1|1].lazy);
    }
    int mid=t[s].l+t[s].r>>1;
    if(r<=mid){
        return query(s<<1,l,r);
    }
    else {
        if(l>mid) return query(s<<1|1,l,r);
        else return Max(query(s<<1,l,mid),query(s<<1|1,mid+1,r));
    }
   t[s].sum=Max(t[s<<1].sum,t[s<<1|1].sum);
}
signed main(){
    int T;scanf("%d",&T);int ca=0;
    while(T--){
        int n,m;scanf("%d%d",&n,&m);
        build(1,1,m);
        for(int i=1;i<=n;++i){
            int t,x;
            b[i].t=read();
            b[i].x=read();
        }
        sort(b+1,b+n+1,cmp);
        int cnt=1;
        a[1]=b[1];
        for(int i=2;i<=n;i++) if(b[i].t!=a[cnt].t){
            a[++cnt]=b[i];
        }
        for(int i=1;i<=cnt;i++){
            for(int k=0;;++k){
                int l=2*k*a[i].t+1;
                int r=l-1+a[i].t;
                r=Min(r,m);
                if(l<=m && r<=m)update(1,l,r,a[i].x);
                if(l>=m || r==m) break;
            }a
        }
        printf("Case #%d:",++ca);
        for(int i=1;i<=m;++i) printf(" %d",query(1,i,i));
        puts("");
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我不会c语言

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值