P1486 [NOI2004]落ち込んだテラー

トピック

トピック

アイデア

下限を削除して設定しないと、バランスツリーボードになり、下限を削除して設定するのが困難になります。
私はいくつかの問題の解決策を、主に2つの方法で読みました。

  1. 現在の下限を挿入し、その合計を左側のサブツリーに転送してから、左側のサブツリーを削除します。
  2. プレフィックスを列挙して、1つずつ削除します。

2つの方法にはそれぞれ長所と短所があります。前者は多くのスペースを浪費し、後者は長い時間がかかります。
cspでスペースを爆発させるプレイヤーとして、私は個人的に後者をお勧めします。
2つ目は、下限を変更することです。これ
により、このアイデアを使用できます。つまり、全員が賃金を引き上げます。これは、下限の引き下げに相当し、その逆も同様です。
したがって、合計を使用して昇給額を記録します。
しかし、後の方には処理資金がないことがわかりますので、事前にお金を取り除いて金額を増やし、お問い合わせの際に追加します。
コード:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
using namespace std;
struct Treap{
    
    
	long long l,r;//左右子编号 
	long long v,d;//v权值(真),d随机值(旋转用) 
	long long cnt,size;//cnt重复个数,size子树大小 
} a[300010];
long long tot,root=1,n,inf=0x7fffffff,rank1,v;
long long New()//新建节点 
{
    
    
	a[++tot].v=v;
	a[tot].d=rand();
	a[tot].cnt=1;
	a[tot].size=1;
	return tot;
}
void Up(long long x)
{
    
    
	a[x].size=a[a[x].l].size+a[a[x].r].size+a[x].cnt;
	return; 
}
void Build()
{
    
    
	v=-inf;
	root=New();
	v=inf;
	New();
	a[root].r=2;
	//避免越界
	Up(root);
	return;
}
long long GRBV(long long x)//求排名 
{
    
    
	if (x==0) return -1;//未查询到结果
	if (v==a[x].v) return a[a[x].l].size+1;//返回排名
	if (v<a[x].v) return GRBV(a[x].l); 
	return GRBV(a[x].r)+a[a[x].l].size+a[x].cnt;//类似二分 
}
long long GVBR(long long x)//求值 
{
    
    
	if (x==0) return -1;//未查询到结果
	if (a[a[x].l].size>=rank1) return GVBR(a[x].l);//二分 
	if (a[a[x].l].size+a[x].cnt>=rank1) return a[x].v;//返回结果 
	rank1-=a[a[x].l].size+a[x].cnt;
	return GVBR(a[x].r);//二分 
}
void zig(long long &x)//右旋(左节点变父节点) 
{
    
    
	long long y=a[x].l;
	a[x].l=a[y].r,a[y].r=x,x=y;
	Up(a[x].r),Up(x);
	return;
}
void zag(long long &x)//左旋(右节点变父节点) 
{
    
    
	long long y=a[x].r;
	a[x].r=a[y].l,a[y].l=x,x=y;
	Up(a[x].l),Up(x);
	return;
}
void Insert(long long &x)//插入 
{
    
    
	if (x==0)//新建节点 
	{
    
    
		x=New();
		return;
	}
	if (v==a[x].v)//已有节点,个数+1 
	{
    
    
		a[x].cnt++,Up(x);
		return;
	}
	if (v<a[x].v)//二分 
	{
    
    
		Insert(a[x].l);
		if (a[x].d<a[a[x].l].d) zig(x);
		Up(x);
		return;
	}
	Insert(a[x].r);
	if (a[x].d<a[a[x].r].d) zag(x);
	Up(x);
	return;
}
long long GP()//求前缀 
{
    
    
	long long ans,x=root;
	while (x)
	{
    
    
		if (v>a[x].v)
		{
    
    
			ans=a[x].v,x=a[x].r;
		}
		else x=a[x].l;
	}
	return ans;
}
long long GN()//求后缀 
{
    
    
	long long ans,x=root;
	while (x)
	{
    
    
		if (v<a[x].v)
		{
    
    
			ans=a[x].v,x=a[x].l;
		}
		else x=a[x].r;
	}
	return ans;
}
long long x,last=0,ans=0,ss=0,mn;
void Erase(long long &x)//删除 
{
    
    
	if (x==0) return;
	if (v==a[x].v)
	{
    
    
		if (a[x].cnt>1)
		{
    
    
			a[x].cnt--,Up(x);
			return;//多个,删一个 
		}
		if (a[x].l||a[x].r)//有子节点
		{
    
    
			if (a[x].r==0||a[a[x].l].d>a[a[x].r].d) zig(x),Erase(a[x].r);
			else zag(x),Erase(a[x].l);//旋转,然后删除节点(保证平衡) 
			Up(x);
		}
		else x=0;
		return;
	}
	if (v<a[x].v)
	{
    
    
		Erase(a[x].l);
	}
	else
	{
    
    
		Erase(a[x].r);
	}//二分 
	Up(x);
	return;
}
int main()
{
    
    
	//srand(114514);
	Build();
	cin>>n>>mn;
	char o;
	while (n--)
	{
    
    
		cin>>o>>x;
		if (o=='I')
		{
    
    
			v=x-last;
			if (v>=mn)
			{
    
    
				ss++,ans++;
				Insert(root);
			}
		}
		if (o=='S')
		{
    
    
			mn+=x;
			last-=x;
			v=mn;
			while (GP()!=-inf)
			{
    
    
				v=GP();
				Erase(root);
				v=mn;
				ans--;
			}
		}
		if (o=='A')
		{
    
    
			last+=x;
			mn-=x;
		}
		if (o=='F')
		{
    
    
			if (ans<x)
			{
    
    
				cout<<-1<<endl;
			}
			else
			{
    
    
				rank1=ans-x+2;
				cout<<GVBR(root)+last<<endl;
			}
		}
	}
	cout<<ss-ans<<endl;
    return 0;
}

おすすめ

転載: blog.csdn.net/weixin_49843717/article/details/114764785