[Codeforces264E][线段树][DP]Roadside Trees

39 篇文章 0 订阅
33 篇文章 0 订阅

翻译

1 ∼ n 1∼n 1n 的位置能种树,刚开始能种树。
i i i 个时刻会有操作:
1.在一个没种过树的位置 p i p_i pi种一颗高度为 h i h_i hi的树。
2.砍掉第 x i x_i xi棵树,保证这个位置以后不会种树。
每天树会长高 1 1 1
每执行一次操作,输出最长上升子序列长度
任意时刻树的高度不同

题解

看完题…不会做
看完数据范围…有点想法
每次加入的高度不会超过10
每次删除的树不会超过前十个
保证任意时刻没有树的高度是相同的
每个点记录一个 d p [ i ] dp[i] dp[i]表示以他为开头的LIS
显然加入一棵树的时候只会影响最多10棵树的答案
删除一棵树的时候也只会影响最多10棵树的答案
对于加入,你开一棵线段树,把高度>10的树扔进去,以位置为下标
对于删除,再开一棵线段树,把位置>10的树扔进去,以高度为下标
支持最大值
乱搞搞…

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#define LL long long
#define mp(x,y) make_pair(x,y)
#define lc now<<1
#define rc now<<1|1
using namespace std;
inline LL read()
{
	LL f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline void write(int x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+'0');
}
inline void pr1(int x){write(x);printf(" ");}
inline void pr2(int x){write(x);puts("");}

int tim;
struct ph
{
	int h,x;
	ph(){}
	ph(int _h,int _x){h=_h;x=_x;}
}w[200100];int v[200100];
bool cmp1(ph n1,ph n2){return n1.h<n2.h;}
bool cmp2(ph n1,ph n2){return n1.x<n2.x;}
ph li[200100];int pos;
int s[200100],f[200100],ln;
int lowbit(int x){return x&-x;}
void chpos(int x,int c){for(x;x<=200000;x+=lowbit(x))s[x]+=c;}
int findKth(int K)
{
	int now=0,sum=0;
	for(int i=18;i>=0;i--)
		if(now+(1<<i)<=200000&&sum+s[now+(1<<i)]<K)sum+=s[now+(1<<i)],now+=(1<<i);
	return now+1;
}
int mx[2][410000*4];
void modify(int now,int l,int r,int p,int c,int op)
{
	if(l==r){mx[op][now]=c;return ;}
	int mid=(l+r)/2;
	if(p<=mid)modify(lc,l,mid,p,c,op);
	else modify(rc,mid+1,r,p,c,op);
	mx[op][now]=max(mx[op][lc],mx[op][rc]);
}
int query(int now,int l,int r,int ql,int qr,int op)
{
	if(ql>qr)return 0;
	if(l==ql&&r==qr)return mx[op][now];
	int mid=(l+r)/2;
	if(qr<=mid)return query(lc,l,mid,ql,qr,op);
	else if(mid+1<=ql)return query(rc,mid+1,r,ql,qr,op);
	else
	{
		int t1=query(lc,l,mid,ql,mid,op);
		int t2=query(rc,mid+1,r,mid+1,qr,op);
		return max(t1,t2);
	}
}
int n,m;
int ans;
//第一个以位置为下标 高度>10扔进去 
//第二个以高度为下标 位置>10扔进去 
int a[200100];
int main()
{
//	freopen("a.in","r",stdin);
//	freopen("a.out","w",stdout);
	n=read();m=read();
	
	for(int tt=1;tt<=m;tt++)
	{
		int opt=read(),p=read();
		int nw=0;sort(li+1,li+1+pos,cmp1);
		for(int i=1;i<=pos;i++)if(li[i].h+tt<=10)li[++nw]=li[i];
		pos=nw;
		if(opt==1)
		{
			int h=read();a[p]=h-tt+m;chpos(p,1);
			for(int i=1;i<=pos;i++)if(li[i].h+tt<h)modify(1,1,n,li[i].x,0,0),modify(1,1,n+m,li[i].h+m,0,1);
			int hh=query(1,1,n,p,n,0)+1;
			modify(1,1,n,p,hh,0);modify(1,1,n+m,h-tt+m,hh,1);
			sort(li+1,li+1+pos,cmp1);
			for(int i=pos;i>=1;i--)if(li[i].h+tt<h)
			{
				hh=query(1,1,n,li[i].x+1,n,0)+1;
				modify(1,1,n,li[i].x,hh,0);modify(1,1,n+m,li[i].h+m,hh,1);
			}li[++pos]=ph(h-tt,p);
		}
		else
		{
			for(int i=1;i<=p;i++)
			{
				int u=findKth(i);
				modify(1,1,n,u,0,0);modify(1,1,n+m,a[u],0,1);
			}
			int nw=0,u=findKth(p);a[u]=0;chpos(u,-1);
			for(int i=1;i<=pos;i++)if(li[i].x!=u)li[++nw]=li[i];
			pos=nw;
			for(int i=p-1;i>=1;i--)
			{
				u=findKth(i);int hh=query(1,1,n+m,a[u],n+m,1)+1;
				modify(1,1,n,u,hh,0);modify(1,1,n+m,a[u],hh,1);
			}
		}
		pr2(mx[0][1]);
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
引用\[1\]中提到了一种形动态规划的方法来解决CodeForces - 982C问题。在这个问题中,subtree指的是子连通块,而不是子。为了使cnt_white - cnt_black尽可能大,可以使用两次形动态规划来求解。第一次是自底向上的过程,维护一个dp数组,表示以每个节点为根的子中的最大连通块。第二次是自顶向下的过程,处理自底向上过程中无法包含的链所代表的子。在第二次遍历中,需要维护一个sum变量,用于存储链所代表的子的贡献。根据ans\[u\]的正负,决定是否能对相邻的子节点做出贡献。如果ans\[u\]为正,则减去dp\[v\]就是链所代表的子的权值。最终,ans\[u\]代表包含节点u在内的子连通块的最大权值。\[1\] 问题: CodeForces - 982C DP是什么问题?如何解决? 回答: CodeForces - 982C是一个形动态规划问题。在这个问题中,需要求解子连通块的最大权值和,使得cnt_white - cnt_black尽可能大。解决这个问题的方法是使用两次形动态规划。第一次是自底向上的过程,维护一个dp数组,表示以每个节点为根的子中的最大连通块。第二次是自顶向下的过程,处理自底向上过程中无法包含的链所代表的子。在第二次遍历中,需要维护一个sum变量,用于存储链所代表的子的贡献。根据ans\[u\]的正负,决定是否能对相邻的子节点做出贡献。最终,ans\[u\]代表包含节点u在内的子连通块的最大权值。\[1\] #### 引用[.reference_title] - *1* *2* [CodeForces - 1324F Maximum White Subtree(dp)](https://blog.csdn.net/qq_45458915/article/details/104831678)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值