BZOJ 3922: Karin的弹幕 线段树 暴力乱搞

本文介绍了一个关于处理视频弹幕数据的算法问题。主要关注如何高效地对一段等差数列时间内的弹幕数量求最大值及单点修改的操作。通过构建特殊的线段树结构来解决这一挑战。

3922: Karin的弹幕

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 606  Solved: 230
[Submit][Status][Discuss]

Description

Karin在战斗之余的闲暇时光里喜欢上B站看鬼畜视频,尤其喜欢发弹幕。她这天对一个视频的弹幕产生了兴趣,她记录了每个时间点的弹幕数量,并且可能对一段呈等差数列的时间的弹幕数量求最大值;她还可能修改某个时间点的弹幕数量。
为了不在Yuuna面前暴露出她弱爆了的数学能力,保持她傲娇的属性,你需要帮助她。
精简题意:给定一个序列,支持以下操作:①对一段下标是等差数列的子序列进行求最大值操作(参见输入格式);②单点修改。

Input

第一行是一个整数n,
第二行是一个长度为n的整数序列a1...an,
第三行是一个整数m,
接下来m行,每行首先有一个整数op,
然后,若op=0,则之后有两个整数p,v,代表将a[p]的值加上v,
若op=1,则之后有两个整数x0,d,代表询问max{a[x0],a[x0+d],a[x0+2d],...,a[x0+kd]}(x0+kd<=n,x0+(k+1)d>n)。
数据中可能有多余空格。

Output

对每个op=1,单独输出一行,代表该等差子序列的最大值。

Sample Input

【输入样例1】
10
1 6 1 4 9 4 8 2 8 5
10
1 3 3
0 5 4
0 3 8
1 2 5
1 4 8
1 7 5
1 3 6
0 1 2
1 5 3
1 4 9

【输入样例2】
10
-9 -6 2 -10 -2 -6 10 6 -4 -2
10
1 2 3
1 6 3
0 7 8
0 4 -6
0 10 -5
1 10 4
0 3 -8
1 2 4
0 10 -5
1 1 2

Sample Output

【输出样例1】
8
8
4
8
9
13
4

【输出样例2】
6
-4
-7
-6
18

HINT

【数据范围】
1<=n<=70000,
1<=m<=70000,
保证任何时刻abs(a[i])(1<=i<=n)<=2147483647,
0<=op<=1,
1<=p<=n,
abs(v)<=2147483647
1<=x0<=n,
1<=d<=n,
保证涉及的所有数在C++的int内。
2015.4.2新加四组数据

新加数据之后数据范围应该是300000了啊

害我本该AC的代码WA两发 泪

推荐blog

发现我多年未碰数学

连基本不等式都不会了


觉得线段树的维护还是蛮新颖的

#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<complex>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<map>
#include<set>
using namespace std;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
	return x*f;
}
void print(int x)
{if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+'0');}

const int N=300010,M=11,inf=2147483647;

int n,a[N];

struct seg_tree{int mx;}str[M][N];

int pos[M][N],val[M][N],ed[M][N];

inline void pushup(int x,int k)
{str[x][k].mx=max(str[x][k<<1].mx,str[x][k<<1|1].mx);}

void build(int x,int k,int l,int r)
{
	if(l==r){str[x][k].mx=a[val[x][l]];return ;}
	int mid=(l+r)>>1;
	build(x,k<<1,l,mid);build(x,k<<1|1,mid+1,r);
	pushup(x,k);
}

void modify(int x,int k,int l,int r,int aim)
{
	if(l==r){str[x][k].mx=a[val[x][l]];return ;}
	int mid=(l+r)>>1;
	aim<=mid?modify(x,k<<1,l,mid,aim):modify(x,k<<1|1,mid+1,r,aim);
	pushup(x,k);
}

int query(int x,int k,int l,int r,int L,int R)
{
	if(l>=L&&r<=R){return str[x][k].mx;}
	int mid=(l+r)>>1;
	if(mid<L)return query(x,k<<1|1,mid+1,r,L,R);
	else if(mid>=R)return query(x,k<<1,l,mid,L,R);
	else return max(query(x,k<<1|1,mid+1,r,L,R),query(x,k<<1,l,mid,L,R));
}

void initial(int x)
{
	register int i,j,k=0;
	for(i=1;i<=x;++i)
	{
		for(j=i;j<=n;j+=x)
		{
			pos[x][j]=++k;
			val[x][k]=j;
		}
		for(j=i;j<=n;j+=x)ed[x][j]=k;
	}
	build(x,1,1,n);
}

int main()
{
	n=read();
	register int i,opt,j;
	for(i=1;i<=n;++i)a[i]=read();
	int m=min(n/int(log2(n)),10);
	for(i=1;i<=m;++i)initial(i);
	int Q=read();
	while(Q--)
	{
		opt=read();i=read();j=read();
		if(opt&&j<=m)
		{print(query(j,1,1,n,pos[j][i],ed[j][i]));puts("");}
		else if(opt&&j>m)
		{
			int ans=-inf;
			for(;i<=n;i+=j)ans=max(ans,a[i]);
			print(ans);puts("");
		}
		else if(!opt)
		{
			a[i]+=j;
			for(opt=1;opt<=m;++opt)modify(opt,1,1,n,pos[opt][i]);
		}
	}
	return 0;
}
/*
10
1 6 1 4 9 4 8 2 8 5
10
1 3 3
0 5 4
0 3 8
1 2 5
1 4 8
1 7 5
1 3 6
0 1 2
1 5 3
1 4 9

8
8
4
8
9
13
4

10
-9 -6 2 -10 -2 -6 10 6 -4 -2
10
1 2 3
1 6 3
0 7 8
0 4 -6
0 10 -5
1 10 4
0 3 -8
1 2 4
0 10 -5
1 1 2

6
-4
-7
-6
18
*/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值