BZOJ 3747 POI2015 Kinoman 段树

BZOJ 3747 POI2015 Kinoman 段树

大家好,又见面了,我是全栈君,今天给大家准备了Idea注册码。

标题效果:有m点,每个点都有一个权值。现在我们有这个m为点的长度n该序列,寻求区间,它仅出现一次在正确的点区间内值和最大

想了很久,甚至神标题,奔说是水的问题……我醉了

枚举左点 对于每个请求留点右键点 树维护最大值

考虑每一个数对答案的贡献 记录一个数组next表示这个位置上的点下一次出现的位置 那么这个点贡献的作用范围就是[i,next[i]-1] 假设没有next就是[i,n]

于是我们先把全部第一个出现的数对答案的贡献增加线段树 然后从左到右扫一遍 每次统计完答案之后把i对答案的贡献去除 然后把next[i]对答案的贡献增加线段树

这常数我也是醉了……速度倒数第二啥的 正解一定不是这种……

此外POI2015是我穿错年代了?

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 1001001
using namespace std;
struct Segtree{
	Segtree *ls,*rs;
	long long num,mark;
	void Build_Tree(int x,int y);
	void Update(int x,int y,int l,int r,long long val);
	long long Get_Ans(int x,int y,int l,int r);
}*root=new Segtree,mempool[M<<1],*C=mempool;
int n,m;
int a[M],w[M],next[M],last[M];
bool v[M];
long long ans;
void Segtree :: Build_Tree(int x,int y)
{
	int mid=x+y>>1;
	num=0;mark=0;
	if(x==y) return ;
	ls=C++;rs=C++;
	ls->Build_Tree(x,mid);
	rs->Build_Tree(mid+1,y);
}
void Segtree :: Update(int x,int y,int l,int r,long long val)
{
	int mid=x+y>>1;
	if(x==l&&y==r)
	{
		num+=val;
		mark+=val;
		return ;
	}
	if(mark)
	{
		ls->num+=mark;
		rs->num+=mark;
		ls->mark+=mark;
		rs->mark+=mark;
		mark=0;
	}
	if(r<=mid) ls->Update(x,mid,l,r,val);
	else if(l>mid) rs->Update(mid+1,y,l,r,val);
	else ls->Update(x,mid,l,mid,val),rs->Update(mid+1,y,mid+1,r,val);
	num=max(ls->num,rs->num);
}
long long Segtree ::  Get_Ans(int x,int y,int l,int r)
{
	int mid=x+y>>1;
	if(x==l&&y==r)
		return num;
	if(mark)
	{
		ls->num+=mark;
		rs->num+=mark;
		ls->mark+=mark;
		rs->mark+=mark;
		mark=0;
	}
	if(r<=mid) return ls->Get_Ans(x,mid,l,r);
	if(l> mid) return rs->Get_Ans(mid+1,y,l,r);
	return max( ls->Get_Ans(x,mid,l,mid) , rs->Get_Ans(mid+1,y,mid+1,r) );
}
int main()
{
	int i;
	cin>>n>>m;
	for(i=1;i<=n;i++)
		scanf("%d",&a[i]);
	for(i=1;i<=m;i++)
		scanf("%d",&w[i]);
	for(i=1;i<=n;i++)
	{
		if(last[a[i]])
			next[last[a[i]]]=i;
		else
			v[i]=1;
		last[a[i]]=i;
	}
	root->Build_Tree(1,n);
	for(i=1;i<=n;i++)
		if(v[i])
			root->Update(1,n,i,next[i]?next[i]-1:n,w[a[i]]);
	for(i=1;i<=n;i++)
	{
		ans=max(ans, root->Get_Ans(1,n,i,n) );
		root->Update(1,n,i,next[i]?next[i]-1:n,-w[a[i]]);
		if(next[i])
			root->Update(1,n,next[i],next[next[i]]?next[next[i]]-1:n,w[a[next[i]]]);
	}
	cout<<ans<<endl;
}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/117735.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • C++智能指针「建议收藏」

    C++智能指针「建议收藏」一、基础知识介绍二、不带引用计数的智能指针三、带引用计数的智能指针四、shared_ptr和weak_ptr五、多线程访问共享对象的线程安全问题六、自定义删除器

  • pycharm的版本_qq旧版本下载

    pycharm的版本_qq旧版本下载详情链接:https://www.jetbrains.com/pycharm/download/other.html

  • 网易邮箱问候语

    网易邮箱问候语

    2021年11月17日
  • 排序二叉树的实现

    排序二叉树的实现在计算机科学中,二叉树是一种重要的非线性的数据结构。每个结点的度均小于等于2,通常子树称为左子树和右子树。而排序二叉树是二叉树中的一种,其满足:1.如左子树不为空,那么左子树上的结点的值都小于其根上的值;2.如右子树不为空,那么右子树上的结点的值都大于其根上的值;3.其子树也是一个排序二叉树。下面用递归的方式来插入一个结点来满足上述的要求:typedefstructNode{

  • Oracle number数据类型的使用[通俗易懂]

    Oracle number数据类型的使用[通俗易懂]需要首先明白有效位的含义:从左到右,从第一个不为零的数开始计数第一种情况:number后面都是两个正数,第一个数表示有效位,第二个数表示小数点后的位数(也就是精确度,需要进行四舍五入)例如number(2,1)存入的数据有1,0.1,1.666分析过程:存入1:要求有效位小于等于2,所以自动补充0,存入1实际上判断的是1.0是否符合条件,自然可以添加存入0….

  • Java 基础练习题

    Java 基础练习题1.java类名命名规则答:1.大驼峰命名法2.不能以数字开头3.不能使用关键字,但是可以包含关键字4.数字.字母._,$5.见名知意2.java变量名(标识符)的命名规则和注意事项1.小驼峰命名法2.不能以数字开头3.不能使用关键字,但是可以包含关键字4.数字.字母._,$5.见名知意注意事项:1.相同作用域中不允许重复定义2.变量未经初始化,不允许使用3.一条语句可以定义多个相同类型的变量3.求成绩占总成绩的百分比doublescore=90;double

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号