Maximum Rating

题目链接

  • 通过这道题,对Splay有了更深刻的理解
  • Splay的中序遍历代表当前序列,通过查询排名为i的点找到序列中的第i个数,这些信息是完全由Splay的结构提供的
  • 通过Splay的编号,我们则可以访问到原序列对应的节点
  • 其实这道题完全是可以用线段树做的,既然普通线段树不行,那不妨用权值线段树实现【顺序自动机】
  • 数据结构的程序很难通过一般的输出中间结果法调试,因为问题出现的时候往往不是问题产生的时候
  • 你常告诫自己“想清楚了再写代码“,可是这道题的思路难道不清楚吗?是的,思路很清楚,重要的是你该如何实现它呢?
  • 尝试了一种新的Splay树写法,即忽视相同的权值,使得节点的标号也能存储一定的信息;但这样做的代价是,你没办法直接通过两遍Splay轻松地定位到要删除的节点,这是你当初纠结的点之一

是一道典型的 转换题意->选择数据结构->码 的题目,也是“熟悉程序语法”到“合格竞赛选手”的门槛。

点击查看代码
#include <bits/stdc++.h>
using namespace std;
int n,h[200005],root;
struct t1
{
	int fa,s[2];
	int va,size;
	long long sum;
	t1()
	{
		fa=s[0]=s[1]=0;
		va=size=sum=0;
	}
}t[200005];
bool get(int x)
{
	return x==t[t[x].fa].s[1];
}
void maintain(int x)
{
	t[x].sum=t[t[x].s[0]].sum+t[t[x].s[1]].sum+t[x].va;
	t[x].size=t[t[x].s[0]].size+t[t[x].s[1]].size+1;
}
void rotate(int x)
{
	int y=t[x].fa,z=t[y].fa,opt=get(x);
	t[y].s[opt]=t[x].s[opt^1];
	if(t[x].s[opt^1])
	{
		t[t[x].s[opt^1]].fa=y;
	}
	t[x].s[opt^1]=y;
	t[y].fa=x;
	t[x].fa=z;
	if(z)
	{
		t[z].s[y==t[z].s[1]]=x;
	}
	maintain(y);
	maintain(x);
}
void update(int x)
{
	maintain(x);
	if(t[x].fa)
	{
		update(t[x].fa);
	}
}
void Splay(int x,int k)
{
	update(x);
	while(t[x].fa!=k)
	{
		int y=t[x].fa,z=t[y].fa;
		if(z!=k)
		{
			if(get(x)==get(y))
			{
				rotate(y);
			}
			else
			{
				rotate(x);
			}
		}
		rotate(x);
	}
	if(!k)
	{
		root=x;
	}
}
void output(int p)
{
	if(!p)
	{
		return;
	}
	output(t[p].s[0]);
	cout<<" "<<t[p].va;
	output(t[p].s[1]);
}
int rnk(int p,int va)
{
	if(t[t[p].s[0]].size==va-1)
	{
		return p;
	}
	else if(t[t[p].s[0]].size<va-1)
	{
		return rnk(t[p].s[1],va-t[t[p].s[0]].size-1);
	}
	else
	{
		return rnk(t[p].s[0],va);
	}
}
long long ask(int p)
{
	Splay(rnk(root,1),0);
	Splay(rnk(root,p+2),rnk(root,1));
	return t[t[rnk(root,p+2)].s[0]].sum;
}
void insert(int x)
{
	int p=root;
	while(p)
	{
		if(t[x].va>t[p].va)
		{
			if(!t[p].s[1])
			{
				t[p].s[1]=x;
				t[x].fa=p;
				Splay(x,0);
				return;
			}
			p=t[p].s[1];
		}
		else
		{
			if(!t[p].s[0])
			{
				t[p].s[0]=x;
				t[x].fa=p;
				Splay(x,0);
				return;
			}
			p=t[p].s[0];
		}
	}
}
int pre()
{
	int cur=t[root].s[0];
	while(t[cur].s[1])
	{
		cur=t[cur].s[1];
	}
	Splay(cur,0);
	return cur;
}
int merge(int x,int y)
{
	if(!x)
	{
		return y;
	}
	if(!y)
	{
		return x;
	}
	int p=pre();
	t[p].s[1]=y;
	t[y].fa=p;
	maintain(p);
	return p;
}
void clear(int x)
{
	t[x].fa=t[x].s[0]=t[x].s[1]=t[x].sum=t[x].size=0;
}
void erase(int x)
{
	Splay(x,0);
	t[t[x].s[0]].fa=t[t[x].s[1]].fa=0;
	root=merge(t[x].s[0],t[x].s[1]);
	clear(x);
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int q,maxn=0;
	cin>>n>>q;
	t[1].va=INT_MIN;
	t[n+2].va=INT_MAX;
	t[1].s[1]=n+2;
	t[n+2].fa=1;
	maintain(n+2);
	maintain(1);
	root=1;
	h[1]=1;
	for(int i=2;i<=n+1;i++)
	{
		cin>>t[i].va;
		insert(i);
		h[i]=i;
		maxn+=(t[i].va>0);
	}
	auto check=[](int p)
	{
		return ask(p)<=0;	
	};
	for(int i=1;i<=q;i++)
	{
		int x,v;
		cin>>x>>v;
		maxn-=(t[x+1].va>0);
		maxn+=(v>0);
		t[x+1].va=v;
		erase(x+1);
		insert(x+1);
		int p=partition_point(h+1,h+n+1,check)-h;
		int minn=n+1-p;
		cout<<maxn-minn+1<<"\n"; 
	}
	return 0;
}
posted @ 2024-10-14 19:50  D06  阅读(3)  评论(0编辑  收藏  举报