2020 CCPC 绵阳站 J Joy of Handcraft (并查集思想)

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 t​i​​ and a luminance x​i​​. 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 ith bulb is on, its luminance will be x​i​​, 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(1T100) − 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(1n,m105) − 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(1ti,xi105) − 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))=105105,显然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)=2105,可以接受了

写的时候不知道这个思想叫啥,现在来看有点并查集的意思。也看见有用线段树和分块实现的,不过我觉得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;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值