Little Horse always does some handcrafts, which is full of joy. This time, he builds a circuit that can turn on and off the bulbs periodically.
There are n bulbs in the circuit, the i-th of which has a period ti and a luminance xi. Formally, the i-th bulb will be turned on from the ( 2 k t i + 1 ) − t h (2kt_i+1)-th (2kti+1)−th second to the ( 2 k t i + t i ) − t h (2kt_i+ti)-th (2kti+ti)−th second, and it will be turned off from the ( 2 k t i + t i + 1 ) (2kt_i+t_i+1) (2kti+ti+1)-th second to the ( 2 k t i + 2 t i ) − t h (2kt_i+2t_i)-th (2kti+2ti)−th second, k=0,1,2,… When the i − t h i-th i−th bulb is on, its luminance will be xi, otherwise its luminance will be 0.
Now, Little Horse wants to know, for each second from the first second to the m-th second, what’s the maximum luminance among all the bulbs.
Input
The first line of the input contains an integer T ( 1 ≤ T ≤ 100 ) T (1≤T≤100) T(1≤T≤100) − the number of test cases.
The first line of each test case contains two integers n , m ( 1 ≤ n , m ≤ 105 ) n,m (1≤n,m≤105) n,m(1≤n,m≤105) − the number of bulbs, and the number of integers you need to output. The sum of n n n and the sum of m m m will not exceed 2 × 1 0 5 2×10^5 2×105.
Then in the next n lines, the i-th line contains two integers t i , x i ( 1 ≤ t i , x i ≤ 1 0 5 ) t_i,x_i (1≤t_i,x_i≤10^5) ti,xi(1≤ti,xi≤105) − the period and the luminance of the i-th bulb.
Output
The x-th test case begins with Case #x:, and there follow m integers. The i-th integer indicates the maximum luminance among all the bulbs in the i-th second. If no bulb is on in the i-th second, output 0.
Sample Input
3
2 3
1 1
2 2
2 5
1 2
2 3
3 3
1 1
1 2
1 3
Sample Output
Case #1: 2 2 1
Case #2: 3 3 2 0 3
Case #3: 3 0 3
分析
题目大意:给你n个灯和m个时间点。每个灯泡都由个周期 t i t_i ti和亮度 x i x_i xi。从 ( 2 k t i + 1 ) (2kt_i+1) (2kti+1)秒到 ( 2 k t i + t i ) (2kt_i+ti) (2kti+ti) 秒灯是亮的 ,而后熄灭 t i t_i ti秒,再变量 t i t_i ti秒,循环往复。问你每个时刻所有灯泡最大亮度是多少。
首先暴力的想法是开一个ans数组,然后对每个灯泡用O(m)时间跑一遍。对所有样例最大总时间开销为 O ( m a x ( n ) ∗ m a x ( m ) ) = 1 0 5 ∗ 1 0 5 O(max(n)*max(m))=10^5*10^5 O(max(n)∗max(m))=105∗105,显然TLE。
考虑建立一个jmp数组,初始时jmp[i]=i。jmp[i]代表访问到i时可以省略到中间的部分,直接跳到jmp[i]。对每组样例中的所有灯泡,先用map去重,再按照 x x x从大到小排个序。用排序好的数组来跑ans,分两种情况:
- ans[i]==0,即ans未知,更新ans[i]=当前x,并令jmp[i-1]=i
- ans[i]!=0,ans已知,此时借助jmp数组快速将i跳到下一个需要访问的地方
这样算法的最大总时间开销为 O ( ∑ n ) = 2 ∗ 1 0 5 O(\sum n)=2*10^5 O(∑n)=2∗105,可以接受了
写的时候不知道这个思想叫啥,现在来看有点并查集的意思。也看见有用线段树和分块实现的,不过我觉得170多人能过得题应该不至于上那种重武器吧。
AC代码:
#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e5+300;
int jmp[MAXN];
int ans[MAXN];
struct node{
int t,x;
}a[MAXN];
void init(int m){
memset(ans,0,sizeof(int)*(m+100));
for(int i=0;i<=m+100;i++){
jmp[i]=i;
}
}
int cmp(node &a, node &b){
return a.x>b.x;
}
// 求jmp,顺便更新jmp,有点并查集的意思
int dfs(int id){
if(jmp[id]!=id){
jmp[id]=dfs(jmp[id]);
}
return jmp[id];
}
void solve(){
map<int,int> mp;
mp.clear();
int cnt=0;
int n,m;
scanf("%d%d",&n,&m);
init(m);
while(n--){
int t,x;
scanf("%d%d",&t,&x);
if(mp.count(t)==0 || mp[t]<x){
mp[t]=x;
}
}
for(map<int,int>::iterator iter=mp.begin();iter!=mp.end();iter++){
a[cnt].t=iter->first;
a[cnt].x=iter->second;
cnt++;
}
sort(a,a+cnt,cmp);
// 亮(2kt,2kt+t-1) 暗(2kt+t,2kt+2t-1)
for(int id=0;id<cnt;id++){
int x=a[id].x;
int t=a[id].t;
for(int i=0;i<m;){
int r=min(i-(i%t)+t,m); // 2kt+t
//printf("i:%d r:%d\n",i,r);
for(;i<r;i++){
if(ans[i]){
i=dfs(i);
}
else {
ans[i]=x;
if(i) jmp[i-1]=i;
}
}
// 对齐到下个2kt
if((i/t)%2==1){
i=i+t-i%t;
}
}
}
for(int i=0;i<m;i++){
if(i) putchar(' ');
printf("%d",ans[i]);
}
return;
}
int main(){
int T;
scanf("%d",&T);
for(int kase=1;kase<=T;kase++){
printf("Case #%d: ",kase);
solve();
putchar('\n');
}
return 0;
}