每个灯泡会闪ti分钟,然后灭ti分钟。
灯泡闪的时候亮度为bi
最后问每分钟最亮的亮度是多少。
首先先对灯泡排序,这样相同t值的不重复更新
灯泡去重之后最多只有m个。
线段树维护”时间“这个区间上的最大值。
最多的情况下,m要被更新m/1+m/2+m/3…+m/m=mlogm
区间个数是个调和级数
最后乘上线段树的logm,时间复杂度为mloglogm,可以ac
#include<bits/stdc++.h> #define inf 1e18 #define ll long long #define ull unsigned long long #define int long long #define PI acos(-1.0) #define PII pair<int,int> using namespace std; const int N = 2e5+7 , M = N * 2; const int mod = 1e9+7; int m,p,n,las,vis[N]; struct bumb{ int t,x; }b[N]; int cmp(bumb xx,bumb yy){ return xx.x>yy.x; } struct node{ int l,r; int v; int lz; }tr[N*4]; void pushdown(int u,int l,int r){ tr[l].lz = max(tr[l].lz,tr[u].lz); tr[r].lz = max(tr[r].lz,tr[u].lz); tr[l].v = max(tr[l].v,tr[u].lz); tr[r].v = max(tr[r].v,tr[u].lz); tr[u].lz = 0; } void pushdown(int u){ pushdown(u,u<<1,u<<1|1); } void pushup(int u){ tr[u].v = max(tr[u<<1].v,tr[u<<1|1].v); } void build(int u,int l,int r){ tr[u]={l,r,0,0}; if(l==r) return ; int mid = l + r >>1; build(u<<1,l,mid);build(u<<1|1,mid+1,r); pushup(u); } void modify(int u,int l,int r,int k){ if(l<=tr[u].l&&r>=tr[u].r){ tr[u].lz = max(tr[u].lz,k); tr[u].v = max(tr[u].v,k); return ; } pushdown(u); int mid = tr[u].l + tr[u].r >>1; if(l<=mid) modify(u<<1,l,r,k); if(r>mid) modify(u<<1|1,l,r,k); pushup(u); } int query(int u,int l,int r){ if(l<=tr[u].l&&r>=tr[u].r) return tr[u].v; pushdown(u); int ans=0; int mid=tr[u].l+tr[u].r>>1; if(l<=mid) ans=max(ans,query(u<<1,l,r)); if(r>mid) ans=max(ans,query(u<<1|1,l,r)); return ans; } void solve(){ memset(vis,0,sizeof(vis)); scanf("%lld%lld",&n,&m); for(int i=1;i<=n;++i) scanf("%lld%lld",&b[i].t,&b[i].x); sort(b+1,b+1+n,cmp); build(1,1,m); for(int i=1;i<=n;++i){ if(vis[b[i].t]==1) continue; vis[b[i].t]=1; int st=1,ed=b[i].t; while(st<=m){ modify(1,st,min(ed,m),b[i].x); st=st+2*b[i].t;ed=ed+2*b[i].t; } } for(int i=1;i<=m;++i) printf(" %lld",query(1,i,i)); printf(" "); } signed main(){ int t=1; scanf("%lld",&t); for(int _=1;_<=t;++_){ printf("Case #%lld:",_); solve(); } return 0; }
线段树的做法会过于繁琐
如果从大到小染色,那么先染色的时间点一定不会再被更优的更新
在这里可以用并查集来维护已经染色的区间
这样就可以快速的跳过染色过的区间
#include<bits/stdc++.h> #define inf 1e18 #define ll long long #define ull unsigned long long #define int long long #define PI acos(-1.0) #define PII pair<int,int> using namespace std; const int N = 2e5+7 , M = N * 2; const int mod = 1e9+7; int m,p,n,las,vis[N],ans[N],fa[N]; struct bumb{ int t,x; }b[N]; int cmp(bumb a,bumb b){ return a.x>b.x; } int find(int x){ if(x == fa[x]) return x; return fa[x]=find(fa[x]); } void solve(){ memset(vis,0,sizeof(vis)); scanf("%lld%lld",&n,&m); for(int i=1;i<=n;++i){ scanf("%lld%lld",&b[i].t,&b[i].x); } for(int i=1;i<=m;++i){ ans[i] = 0;fa[i] = i; } sort(b+1,b+1+n,cmp); for(int i=1;i<=n;++i){ if(vis[b[i].t]==1) continue; vis[b[i].t]=1; for(int st = 1;st <= m;st=st+2*b[i].t){//区间起点 for(int pos = st;pos<st+b[i].t && pos<=m;pos++){//更新区间 if(ans[pos]==0) ans[pos]=b[i].x,fa[pos-1]=pos; else pos = find(pos);//直接跳到已经染色过的末尾 } } } for(int i=1;i<=m;++i) printf(" %lld",ans[i]); printf(" "); } signed main(){ int t=1; scanf("%lld",&t); for(int _=1;_<=t;++_){ printf("Case #%lld:",_); solve(); } return 0; }