题意:给了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;
}