洛谷写题笔记

P3863 序列

思路:
第一步先利用差分思想去构成每个数

标记每个差分,从左向右逐步生成每个数的时间线(分块的范围)
由于差分是从左向右,故遍历每个数的位置生成的时间线都是相对应的时间线。

然后转换了一个经典问题,
对一个数进行几个操作
在某一时刻加上x
问这时间段有多少时刻是大于某数的。

方法 , 我们对时间分块 , 对每个分块进行排序 , 由小到大排序 ,然后如果查询是覆盖当前的块区间
,我们采取的块区间操作是二分 , 而不在块区间我们则采取一个暴力求个数的策略。

故该题思路明确

然后对每个数进行时间分块

细节:我们在分块的时候我们先把要分的块与保存的数据独立开来(分块分的是时间)
每次对某一时刻改变数值,改变的是该时刻后面所有数的值,我们保存的是与原来初始值的差(因为用的差分),最后的答案也是求大于与原来初始值的差的个数,我们对其进行一个从1 - 该时刻 - 1的区间分块。

代码正在生成中
在这里我先放一下洛谷维多利加.德.布诺瓦的露天图书馆大佬的代码

#include "bits/stdc++.h"
using namespace std;
#define int long long
const int Len = 2e5 + 5 , SIZE = 525;
int n,m,L[SIZE],R[SIZE],t,cntu,cntq,Print[Len],pos[Len],tag[SIZE];
int A[Len],a[Len],b[Len];
struct node
{
	int idx,val,tim,id,ans;
	node(){idx = 0 , val = 0 , tim = 0;}
	node(int IDX,int VAL,int TIM,int ID){idx = IDX , val = VAL , tim = TIM , id = ID;}
}Upd[Len] , Ques[Len];
bool cmp(node x , node y){return x.idx < y.idx;}
bool cmpd(node x,node y){return x.tim < y.tim;}
void Init()
{
	t = sqrt(m + 1); 
	for(int i = 1 ; i <= t ; i ++) L[i] = (i - 1) * t + 1 , R[i] = i * t;
	if(R[t] < m + 1) R[t] = m + 1;
	for(int i = 1 ; i <= t ; i ++)
		for(int j = L[i] ; j <= R[i] ; j ++) pos[j] = i;
	for(int i = 1 ; i <= t ; i ++) sort(b + L[i] , b + R[i] + 1);
}
void maintain(int t)
{
	for(int i = L[t] ; i <= R[t] ; i ++) b[i] = a[i];
	sort(b + L[t] , b + R[t] + 1);
}
void update(int l,int r,int val)
{
	int Ll = pos[l] , Rr = pos[r];
	if(Ll == Rr)
	{
		for(int i = l ; i <= r ; i ++) a[i] += val;
		maintain(Ll);
		return;
	}
	for(int i = l ; i <= R[Ll] ; i ++) a[i] += val;
	maintain(Ll);
	for(int i = Ll + 1 ; i <= Rr - 1 ; i ++) tag[i] += val;
	for(int i = L[Rr] ; i <= r ; i ++) a[i] += val;
	maintain(Rr); 
}
int query(int l,int r,int val)
{
	int Ll = pos[l] , Rr = pos[r] , res = 0;
	if(Ll == Rr)
	{
		for(int i = l ; i <= r ; i ++) if(a[i] >= val - tag[Ll]) res ++;
		return res;
	} 
	for(int i = l ; i <= R[Ll] ; i ++) if(a[i] >= val - tag[Ll]) res ++;
	for(int i = Ll + 1 ; i <= Rr - 1 ; i ++) res += R[i] - (lower_bound(b + L[i] , b + R[i] + 1 , val - tag[i]) - b) + 1;
	for(int i = L[Rr] ; i <= r ; i ++) if(a[i] >= val - tag[Rr]) res ++;
	return res;
}
signed main()
{
	scanf("%lld %lld",&n,&m);
	for(int i = 1 ; i <= n ; i ++) scanf("%lld",&A[i]);
	Init();
	for(int k = 1 ; k <= m ; k ++)
	{
		int opt;scanf("%lld",&opt);
		if(opt == 1)
		{
			int l,r,x;scanf("%lld %lld %lld",&l,&r,&x);
			Upd[++ cntu] = node(l , x , k + 1 , 0);
			Upd[++ cntu] = node(r + 1 , -x , k + 1 , 0);
		}
		if(opt == 2)
		{
			int p,y;scanf("%lld %lld",&p,&y);
			Ques[++ cntq] = node(p , y , k + 1 , k);
		}
	}	
	sort(Upd + 1 , Upd + 1 + cntu , cmp);
	sort(Ques + 1 , Ques + 1 + cntq , cmp);
	//for(int i = 1 ; i <= cntu ; i ++) printf("%lld %lld %lld %lld\n",Upd[i].idx,Upd[i].val,Upd[i].tim,Upd[i].id,Upd[i].ans);
	int num = 1;
	for(int i = 1 ; i <= cntq ; i ++) 
	{
		while(num <= cntu && Upd[num].idx <= Ques[i].idx) 
		{
			update(Upd[num].tim , m + 1 , Upd[num].val);
			num ++;	
		}
		//printf("%lld %lld %lld\n",Ques[i].tim,Ques[i].val,Ques[i].idx);
		Ques[i].ans = query(1 , Ques[i].tim - 1 , Ques[i].val - A[Ques[i].idx]);
	}
	sort(Ques + 1 , Ques + 1 + cntq , cmpd);
	for(int i = 1 ; i <= cntq ; i ++) printf("%lld\n",Ques[i].ans);
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值