Joy of Handcraft Gym - 102822J(线段树或差分)

Posted Jozky86

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Joy of Handcraft Gym - 102822J(线段树或差分)相关的知识,希望对你有一定的参考价值。

Joy of Handcraft Gym - 102822J

题意:

每个灯有亮的周期和亮度,问1~m这段时间灯光最亮是多少

题解:

线段树维护区间最大值
根据灯的周期向这段区间加亮度k,然后利用线段树维护区间最大值
但是这样会超时,加个小优化就ac了(670ms)
我们考虑,因为题目只要求最亮的一段,而且所有灯亮的时间起点是一样的,也就是如果两个灯周期一样,只有亮度高的才会有用,所有我们将所有灯按照亮度排序,每加完一组灯,记录该周期,后面再出现该周期的就不用加了。因此所有的区间数量为Σi->n(m/ti)= mlogn

代码:

#include<bits/stdc++.h>
#define debug(a,b) printf("%s = %d\\n",a,b);
typedef long long ll;
using namespace std;

inline int read(){
   int s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);
   return s*w;
}
const int maxn=1e5+9;
struct node{
	int time,light;
}a[maxn];
struct tree{
	int l,r;
	int lazy;
	int sum;
}tr[maxn<<2];
bool cmp(node a,node b){
	return a.light>b.light;
}
void solve(int rt,int val){
	tr[rt].sum=max(tr[rt].sum,val);
	tr[rt].lazy=max(tr[rt].lazy,val);
} 
void pushdown(int rt){
	solve(rt<<1,tr[rt].lazy);
	solve(rt<<1|1,tr[rt].lazy);
	tr[rt].lazy=0;
}
void pushup(int rt){
	tr[rt].sum=max(tr[rt<<1].sum,tr[rt<<1|1].sum);
}
void build(int rt,int l,int r){
	tr[rt].l=l;
	tr[rt].r=r;
	if(l==r){
		tr[rt].lazy=0;
		tr[rt].sum=0;
		return ;
	}
	int mid=l+r>>1;
	build(rt<<1,l,mid);
	build(rt<<1|1,mid+1,r);
	pushup(rt);
}
void update(int rt,int l,int r,int k){
	if(tr[rt].l>r||tr[rt].r<l)return ;
	if(tr[rt].l>=l&&tr[rt].r<=r){
		solve(rt,k);
		return ;
	}
	if(tr[rt].lazy)pushdown(rt);
	update(rt<<1,l,r,k);
	update(rt<<1|1,l,r,k);
	pushup(rt);
}
int query(int rt,int l,int r){
	if(tr[rt].l>r||tr[rt].r<l)return 0;
	if(tr[rt].l>=l&&tr[rt].r<=r){
		return tr[rt].sum;
	}
	pushdown(rt);
	return max(query(rt<<1,l,r),query(rt<<1|1,l,r));
}
int vis[maxn];
int main()
{
	int t;
	cin>>t;
	int cas=0;
	while(t--){
		int n,m;
		cin>>n>>m;
		memset(tr,0,sizeof(tr));
		memset(vis,0,sizeof(vis));
		build(1,1,m);
		for(int i=1;i<=n;i++){
			scanf("%d%d",&a[i].time,&a[i].light);
		}
		sort(a+1,a+1+n,cmp);
		for(int i=1;i<=n;i++){
			
			if(vis[a[i].time])continue;
			vis[a[i].time]=1;
			for(int j=0;j!=-1;j++){
				
				int l=2*j*a[i].time+1,r=2*j*a[i].time+a[i].time;
			//	printf("l=%d r=%d\\n",l,r);
				if(l>m)break;
				if(r>m)update(1,l,m,a[i].light);
				else update(1,l,r,a[i].light);
			}
			
		}
		printf("Case #%d:",++cas);
		for(int i=1;i<=m;i++){
			printf(" %d",query(1,i,i));
		}
		printf("\\n");
	}
	return 0;
}

方法二 差分

整体思路,我们对所有灯按照灯光从小到达排序,然后利用差分思想来存灯光,add来存这个灯光的开始时刻,del来存结束时刻
如图,红色表示开始时刻,蓝色为删除,红色到蓝色(不含蓝色)这一段均为该灯亮的时刻,从蓝色开始熄灭
在这里插入图片描述
这样存得到add和del,再查询答案时,对于每一时刻,加入当前的灯光开始时刻的灯光亮度,然后删除此刻del中记录的灯光,利用差分来维护
复杂度是(Ologlogm)
时间:904ms
(注意我们对灯光是排过序的,所以输出是ans的尾)

差分代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<set>

using namespace std;

const int MAXN = 4e5+5;

struct bub {
	int t, x;
}b[MAXN];

bool cmp(bub a, bub b) {
	return a.x>b.x;
}

bool vis[MAXN];
vector<int> add[MAXN], del[MAXN];
multiset<int> ans;

void init(int n) {
	for(int i=0;i<=n;++i) {	
		add[i].clear();
		del[i].clear();
	}
	memset(vis, 0, sizeof(vis));
	ans.clear();
}

int main() {
	int T; scanf("%d", &T);
	for(int kase =1;kase<=T;++kase) {
		int n, m; scanf("%d%d", &n, &m);
		init(m);
		for(int i=0;i<n;++i) {	
			scanf("%d%d", &b[i].t, &b[i].x);
		}
		sort(b, b+n, cmp);
		for(int i=0;i<n;++i) {
            if(vis[b[i].t]) continue;
			vis[b[i].t]=true;
			for(int j=0;j<=m/b[i].t+1;j+=2) {
				add[j*b[i].t+1].push_back(b[i].x);
				del[(j+1)*b[i].t+1].push_back(b[i].x);
			}
		}
		printf("Case #%d:", kase);
		for(int i=1;i<=m;++i) {
			for(const auto &x: add[i]) {
				ans.insert(x);
			}
			for(const auto &y: del[i]) {
				//ans.erase(y)是删去集合内所有的元素y
				ans.erase(ans.find(y));
			}
			if(!ans.empty()) printf(" %d", *ans.rbegin());
			else printf(" 0");
		}	
		printf("\\n");		
	}
	return 0;
 }

以上是关于Joy of Handcraft Gym - 102822J(线段树或差分)的主要内容,如果未能解决你的问题,请参考以下文章

CCPC2020绵阳站J - Joy of Handcraft

Gym101137KKnights of the Old Republic(生成树 DP)

what yang wanted to do when he got out of the spaceship was___ the joy with all the chinese 分析

Gym 101666K King of the Waves(dfs)

Gym - 101611D Decoding of Varints(边界值处理)

Gym.102059: 2018-2019 XIX Open Cup, Grand Prix of Korea(寒假gym自训第一场)