Intel Code Challenge Elimination Round C. Destroying Array

题目链接: Intel Code Challenge Elimination Round C. Destroying Array

方法一(在线):

  直接套用线段树动态维护区间最大连续和的模板,将一个数删去等价于改成无穷小。

注意INF必须足够大(也不能太大,建议贴着开,否则会超过LONG LONG)

时间复杂度O(nlogn),是一种可以通过的在线算法,代码量略大。

代码:

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>
#define LL long long
#define CLEAR(xxx) memset(xxx,0,sizeof(xxx))
using namespace std;

const LL maxn=100000+5,inf=100000LL*1000000000LL+5;
LL n;

inline void _read(LL &x){
	char ch=getchar(); bool mark=false;
	for(;!isdigit(ch);ch=getchar())if(ch=='-')mark=true;
	for(x=0;isdigit(ch);ch=getchar())x=x*10+ch-'0';
	if(mark)x=-x;
}
struct node{
	LL Lmax,Rmax,Max,Sum;
}val[maxn*5];
LL s[maxn],sum[maxn],ql,qr,p;
LL getmax(LL x,LL y,LL z){
	if(x>=z&&x>=y) return x;
	if(y>=z) return y;  return z;
}
void maintain(int o,int L,int R){
	if(L==R) return ;
	int mid=(L+R)>>1,ls=o*2,rs=o*2+1;
	val[o].Sum=val[ls].Sum+ val[rs].Sum;
	val[o].Lmax=val[ls].Lmax;
	val[o].Rmax=val[rs].Rmax;
	val[o].Lmax=max(val[o].Lmax ,+val[ls].Sum+val[rs].Lmax);
	val[o].Rmax=max(val[o].Rmax ,val[rs].Sum+val[ls].Rmax);
	val[o].Max=getmax(val[ls].Max,val[rs].Max,val[rs].Lmax+val[ls].Rmax);	
}

void build(int o,int L,int R){
	if(L==R) 
		val[o].Lmax=val[o].Rmax=val[o].Max=val[o].Sum=s[L];
	else {
		int mid=(L+R)>>1;
		build(o*2,L,mid); build(o*2+1,mid+1,R);
		val[o].Sum=sum[R]-sum[L-1];
		maintain(o,L,R);
	}
}

void update(int o,int L,int R){
	if(L==R) 
		val[o].Lmax=val[o].Rmax=val[o].Max=val[o].Sum=s[L];
	else {
		int mid=(L+R)>>1;
		if(p<=mid) update(o<<1,L,mid);
		else update(o*2+1,mid+1,R);
		maintain(o,L,R);
	}
}
node query(int o,int L,int R){
	//cout<<"visiting vertex # "<<o<<endl;
	if(ql<=L&&qr>=R) return val[o];
	int mid=(L+R)>>1;
	if(qr<=mid) return query(o<<1,L,mid);
	else if(ql>mid) return query(o*2+1,mid+1,R);
	else if(ql<=mid&&qr>mid){
		int ls=o*2,rs=ls+1;
		node l=query(ls,L,mid);
		node r=query(rs,mid+1,R);
		node ans;
		ans.Sum=l.Sum+r.Sum;
		ans.Lmax=max(l.Lmax, l.Sum+r.Lmax);
		ans.Rmax=max(r.Rmax, r.Sum+l.Rmax);
		ans.Max=getmax(l.Rmax+r.Lmax, l.Max, r.Max);
		return ans;
	}
}
int main(){
	int i,k,S;
	_read(n);
	for(i=1;i<=n;i++){
		_read(s[i]);
		sum[i]=sum[i-1]+s[i];
	}
	build(1,1,n);
	for(i=1;i<=n;i++){
		_read(p);
		ql=1;qr=n ;
		s[p]=-inf;
		update(1,1,n);
		LL ans=query(1,1,n).Max;
		printf("%I64d\n",ans>-inf ? ans:0);
	}
	return 0;
}

方法2(离线):

考虑该过程反向进行,即每次加入一个数。

L[x]记录x向左最多可以延伸到的端点,

R[x]记录x向右最多可以延伸到的端点。

val[x]记录x所处线段的和。

每次用类似链表的方式维护,注意到添加一个数s[x]只会影响到s[x-1]和s[x+1]所在的区间和(也就是合并了这两个区间)。

每次更新最大和即可。

时间复杂度O(n),比方法一更优。

代码:

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<queue>
#include<vector>
#include<algorithm>

#define xx first
#define yy second
#define LL  long long 
#define CLEAR(xxx) memset(xxx,0,sizeof(xxx))
#define INTpair pair<int,int>
using namespace std;
const int maxn=100000+5,inf=1e9;

int n,s[maxn],op[maxn];
int L[maxn],R[maxn];
LL val[maxn];
vector<LL> ans;

inline void _read(int &x){
	char ch=getchar(); bool mark=false;
	for(;!isdigit(ch);ch=getchar())if(ch=='-')mark=true;
	for(x=0;isdigit(ch);ch=getchar())x=x*10+ch-'0';
	if(mark)x=-x;
}
int main(){
	int i,j;
	_read(n);
	for(i=0;i<=n+1;i++)
		L[i]=R[i]=i,val[i]=-1;
	for(i=1;i<=n;i++)_read(s[i]);
	for(i=1;i<=n;i++)_read(op[i]);
	LL maxsum=0;
	ans.push_back(0);
	for(i=n;i>1;i--){
		int cur=op[i];
		LL x=s[cur];
		val[cur]=s[cur];
		if(val[cur-1]!=-1){
			x+=val[cur-1];
			L[R[cur]]=L[cur-1];
			val[R[cur]]=x;
			R[L[cur-1]]=R[cur];
			val[L[cur-1]]=x;
		}
		if(val[cur+1]!=-1){
			x+=val[cur+1];
			R[L[cur]]=R[cur+1];
			val[L[cur]]=x;
			L[R[cur+1]]=L[cur];
			val[R[cur+1]]=x;
		}
		maxsum=max(maxsum,x);
		ans.push_back(maxsum);
	}
	for(i=ans.size()-1;i>=0;i--)
		printf("%I64d ",ans[i]);
	return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值