BZOJ 3747线段树 &&纪念整完了ubuntu

        终于整完ubuntu了开森~

        好了进入正体,这题不就跟GSS2差不多嘛,记录一个next[i]表示下一个出现i的位置

        然后就各种乱搞啦~

#include <cstdio>
#include <iostream>

using namespace std;

const int MAXN = 1000001;

void read(int &x)
{
	x = 0;
	char c;
	do c = getchar();while (c > '9' || c < '0');
	do x = x*10+c-48, c = getchar();while (c >= '0' && c <= '9');
}

int n,m;
int f[MAXN],w[MAXN];
int next[MAXN],last[MAXN];

struct Node
{
	int l,r;
	long long delta,_max;
};

Node Tree[3*MAXN];

void build(int num,int l,int r)
{
	Tree[num].l = l, Tree[num].r = r;
	if (l == r) return;
	int mid = (l+r)>>1;
	build(num<<1,l,mid);
	build(num<<1|1,mid+1,r);
}

void update(int num)
{
	Node &Lc = Tree[num<<1], &Rc = Tree[num<<1|1];
	long long delta = Tree[num].delta;
	Lc.delta += delta, Lc._max += delta;
	Rc.delta += delta, Rc._max += delta;
	Tree[num].delta = 0;
}

void modify(int num,int l,int r,long long delta)
{
	if (l <= Tree[num].l && Tree[num].r <= r)
	{
		Tree[num]._max += delta;
		Tree[num].delta += delta;
		return;
	}
	update(num);
	int mid = (Tree[num].l+Tree[num].r)>>1;
	if (r <= mid) modify(num<<1,l,r,delta);
	else if (l > mid) modify(num<<1|1,l,r,delta);
	else
	{
		modify(num<<1,l,r,delta);
		modify(num<<1|1,l,r,delta);
	}
	Tree[num]._max = max(Tree[num<<1]._max,Tree[num<<1|1]._max);
}

int main()
{
	read(n);read(m);
	for (int i=1;i<=n;i++) read(f[i]);
	for (int i=1;i<=m;i++) read(w[i]);
	build(1,1,n);
	for (int i=n;i>0;i--)
	{
		next[i] = last[f[i]];
		last[f[i]] = i;
	}
	for (int i=1;i<=m;i++) if (last[i])
	{
		if (!next[last[i]]) modify(1,last[i],n,w[i]);
		else modify(1,last[i],next[last[i]]-1,w[i]);
	}
	long long ans = 0;
	for (int i=1;i<=n;i++)
	{
		ans = max(ans,Tree[1]._max);
		int t = next[i];
		if (t)
		{
			modify(1,i,t-1,-w[f[i]]);
			if (next[t]) modify(1,t,next[t]-1,w[f[i]]);
			else modify(1,t,n,w[f[i]]);
		}
		else modify(1,i,n,-w[f[i]]);
	}
	printf("%lld\n",ans);
	return 0;
}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值