2020CCPC綿陽站 J-Joy of Handcraft (去重 + 線段樹 + 調和級數)
題意:給定n個燈泡,那個燈泡排列在電路板上,然後每個燈泡給定你一個t和x,這個燈泡會在[2kt + 1,2kt + t],k=(0,1,2…)的時間區間內發出亮度為x的光,其他時間內不發光,然後給定你一個m問你:從第一秒到第m秒每一秒時亮度最大的燈的亮度為多少?
輔助:首先我們應該知道調和級數也就是 (1/1 + 1/2 + 1/3 +…+1/n)這個東西的部分和為ln(n)+ 尤拉常數,近似等於logn
思路:所以這道題對於給定的m個區間,因為求得是最大的的亮度為多少,所以我們先排個序,將重複時間區間的最大的亮度拿出來。這樣再去列舉每個t對應的時間區間是,區間總個數就是(m/1 + m/2 + m/3+…+m/m)也就是mlogm個區間(這就可做了嘛),列舉更新每個區間時間複雜度也就是O(m * logm * logn)的時間複雜度,2s 跑 400ms就過去了。
剩下的就是區間更新的基本操作了。
程式碼:
#include <bits/stdc++.h>
//線段樹的正解做法
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 7;
int n,m;
struct node{
int t,x;
}b[MAXN],a[MAXN];
bool cmp(node a,node b){
if(a.t == b.t) return a.x > b.x;//相同時間區間內找出亮度最大的即可
else return a.t < b.t;
}
int tree[MAXN<<2],lazy[MAXN<<2];
void pushup(int rt) { tree[rt] = max(tree[rt<<1],tree[rt<<1|1]); }
void pushdown(int rt){
if(lazy[rt]){
lazy[rt<<1] = max(lazy[rt],lazy[rt<<1]);
lazy[rt<<1|1] = max(lazy[rt],lazy[rt<<1|1]);
tree[rt<<1] = max(tree[rt<<1],lazy[rt]);
tree[rt<<1|1] = max(tree[rt<<1|1],lazy[rt]);
lazy[rt] = 0;
}
}
void build(int rt,int l,int r){
lazy[rt] = 0;
if(l == r){
tree[rt] = 0;
return ;
}
int mid = (l+r)>>1;
build(rt<<1,l,mid);build(rt<<1|1,mid+1,r);
pushup(rt);
}
void modify(int rt,int l,int r,int L,int R,int val){
if(l >= L && r <= R){
lazy[rt] = max(lazy[rt],val);
tree[rt] = max(tree[rt],lazy[rt]);
return ;
}
pushdown(rt);
int mid = (l+r)>>1;
if(L <= mid) modify(rt<<1,l,mid,L,R,val);
if(R > mid) modify(rt<<1|1,mid+1,r,L,R,val);
pushup(rt);
}
int query(int rt,int l,int r,int L,int R){
if(l >= L && r <= R) return tree[rt];
pushdown(rt);
int ans = 0;int mid = (l+r)>>1;
if(L <= mid) ans = max(ans,query(rt<<1,l,mid,L,R));
if(R > mid) ans = max(ans,query(rt<<1|1,mid+1,r,L,R));
return ans;
}
int main(){
int T,cas = 0;
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;i ++){
scanf("%d%d",&b[i].t,&b[i].x);
}
sort(b+1,b+1+n,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];
}
build(1,1,m);
for(int i = 1;i <= cnt;i ++){//這全部的複雜度為O(m*logm*logn)
for(int k = 0;;k ++){
int l = k*2*a[i].t + 1,r = (k*2+1)*a[i].t;
r = min(r,m);//有些區間的長度可能右端點超過m 取個min
if(l <= m && r <= m) modify(1,1,m,l,r,a[i].x);
if(l >= m || r == m) break;
}
}
printf("Case #%d:",++cas);
for(int i = 1;i <= m;i ++){
printf(" %d",query(1,1,m,i,i));
}
printf("\n");
}
return 0;
}
相關文章
- 線段樹模板重製(自寫自用)
- 數列求和【線段樹基礎】
- 線段樹
- 線~段~樹
- 山海經:線段樹維護最大子段和
- 調和級數
- 【主席數】可持續化線段樹
- 綿陽哪裡有開發票
- 01 線段樹
- 線段樹--RMQMQ
- 【模版】線段樹
- 線段樹模板
- 線段樹 hate it
- TZOJ 8472 : Tree (重鏈剖分+線段樹) POJ 3237
- 線段樹維護區間等差數列
- ut.cpp 最大線段並減線段交 [線段樹]
- 【Leetcode每日一題】327. 區間和的個數(線段樹/樹狀陣列)LeetCode每日一題陣列
- 李超線段樹
- 線段樹進階
- 權值線段樹
- 線段樹筆記筆記
- Segment Tree(線段樹)
- 線段樹入門
- 洛谷題單指南-線段樹-P3373 【模板】線段樹 2
- 懶標記線段樹
- 可持久化線段樹持久化
- 線段樹(超詳解)
- 線段樹 transformation——hdu 4578ORM
- 深入理解線段樹
- 線段樹簡單思路
- 線段樹擴充套件套件
- 第二課——線段樹
- 線段樹模板總結
- 線段樹(毒瘤)總結
- POJ 3667 Hotel 線段樹
- poj 2667 hotel 線段樹
- 線段樹 - 多組圖帶你從頭到尾徹底理解線段樹
- 資料結構之樹( 線段樹,字典樹)資料結構