CF264E Roadside Trees (线段树+暴力)

qwq校内模拟赛的 t 3 t3

t 1 t1 贼自闭。

首先,我们来考虑如何更新一个点的 L I S LIS

一个比较 n a i v e naive 的想法就是我们对于每个点记录以他为开头的的 L I S LIS 长度。

如果我们选择用这个位置之后的所有位置的 d p dp 值+1来更新的话,貌似无法判断这个 d p dp 值对应的高度是不是合法的。

而我们如果选择用高度大于这个点的 d p + 1 dp值+1 来更新的话,又无法处理位置的问题。

但是我们会发现数据范围中,每次加入一棵树的高度和砍掉一个树的位置的范围是[1,10]$,是不是可以从这里下手呢?

首先我们定义 p o s [ i ] pos[i] 表示高度是 i i 的位置是哪个, h [ i ] h[i] 表示第 i i 个位置的高度是多少。

然后根据上面的思路,我们不难发现,我们肯定是要建两颗线段树的,一颗以位置以下标,一颗是高度为下标,权值都是 d p dp 值。

首先考虑插入操作,对于每次插入,实际上我们只会修改不超过十个位置的 d p dp 值,我们将 h h h 9 h-9 所有高度对应的位置都清零,我们会发现,如果倒着做的话,我们可以直接对于每个点,用其位置之后的 m a x d p maxdp 值+1来更新了,因为小于这个高度的数 d p dp 值都是 0 0 ,不会产生贡献

那么删除是不是也就同理啦?我们一次最多修改 10 10 个位置,会发现可以直接用高度大于该位置的来更新,因为位置在这个位置前面的并不会产生贡献。

扫描二维码关注公众号,回复: 5350358 查看本文章

对于那个整体+的操作,每次只需要维护一个 d e l t a delta ,对读入的 h h h = r e a d ( ) + d e l t a ; h=read()+delta; ,每次 d e l t a delta-- 就ok

需要注意的是,我们对于删除,一定要把这个点所有的相关信息都清空。
qwq

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#define mk make_pair
#define pb push_back
#define ll long long
#include<set>

using namespace std;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
	while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
	return x*f;
}

const int maxn = 2e6+1e2;

struct tree{
	int f[maxn];
	void up(int root)
	{
		f[root]=max(f[2*root],f[2*root+1]);
	}
	void update(int root,int l,int r,int x,int y)
	{
		if (l==r) 
		{
			f[root]=y;
			return;
		}
		int mid = l+r >> 1;
		if (x<=mid) update(2*root,l,mid,x,y);
		else update(2*root+1,mid+1,r,x,y);
		up(root);
	}
	int query(int root,int l,int r,int x,int y)
	{
		if (x<=l && r<=y) return f[root];
		int mid = l+r >> 1;
		int ans=0;
		if (x<=mid) ans=max(ans,query(2*root,l,mid,x,y));
		if (y>mid) ans=max(ans,query(2*root+1,mid+1,r,x,y));
		return ans;
	}
};

tree f,g;
//f is position
//g is height
int n;
int delta = 2e5;
int q;
int pos[maxn];
int height[maxn];
set<int> s;
int a[maxn];

int main()
{
	n=read();q=read();
	int m=delta+10010;
    for (int i=1;i<=q;i++)
    {
    	int opt=read();
    	if (opt==1)
    	{
            int p=read(),h=read()+delta;
            s.insert(p);
            pos[h]=p;
            height[p]=h;
            for(int i=h;i>=h-9;i--)
            {
            	if (!pos[i]) continue;
            	int now = pos[i];
            	f.update(1,1,n,now,0);
            	g.update(1,1,m,i,0);
            }
            for (int i=h;i>=h-9;i--)
            {
            	if (!pos[i]) continue;
            	int now = f.query(1,1,n,pos[i]+1,n)+1; //找位置在这个点后面的
            	f.update(1,1,n,pos[i],now);
            	g.update(1,1,m,i,now);
            }	
        }
        else
        {
        	int k=read();
            set<int>::iterator it = s.begin();
            int cnt=0;
            while (cnt<k) a[++cnt]=*it,++it;
            --it;
            s.erase(it);
            for (int i=1;i<=cnt;i++)
            {
            	if (!height[a[i]]) continue;
            	f.update(1,1,n,a[i],0);
            	g.update(1,1,m,height[a[i]],0);
            }
            for (int i=cnt-1;i>=1;i--)
            {
            	if (!height[a[i]]) continue;
            	int now = g.query(1,1,m,height[a[i]]+1,m)+1;//找高度大的。
            	f.update(1,1,n,a[i],now);
                g.update(1,1,m,height[a[i]],now);
            }
            pos[height[a[cnt]]]=0;
            height[a[cnt]]=0;

        }
        cout<<f.f[1]<<"\n";
        delta--;
    }
	return 0;
}

猜你喜欢

转载自blog.csdn.net/y752742355/article/details/88011681