百折不挠|

Xdik

园龄:25天粉丝:5关注:24

[BJOI2017] 喷式水战改

首先看到要插入序列,所以自然地想到平衡树,那么左儿子就是左边的序列,右儿子就是右边的序列,求这个值的朴素算法是dp吧,就是前 i 个燃料,已经到了第 j 阶段的最大值,但是因为左右儿子是一坨序列,我如果按照这样维护 dp 的话我也不知道右儿子开始的时候到了哪个阶段,所以很自然地想到区间dp,就是把状态改成这个 fp,l,r 表示节点 p 的子树所对应的区间完成了 l,r 这个阶段所能获得的最大值,每次pushup的时候合并一下左右两个区间即可,我实现使用的是fhq

code:

#include <bits/stdc++.h>
#define int long long
#define ull unsigned long long
#pragma GCC optimeze(3)
#pragma GCC optimeze(2)
#define PII pair<int, int>
#define pb push_back
#define fi first
#define se second
#define lowbit(x) (x & (-x))
#define inv(x) (qpow(x,mod-2))
using namespace std;
const int N=4e5+10;
double eps=1e-6;
inline int read(){
	char ch=getchar();bool f=0;int x=0;
	for(;!isdigit(ch);ch=getchar())if(ch=='-')f=1;
	for(;isdigit(ch);ch=getchar())x=(x<<1)+(x<<3)+(ch^48);
	if(f==1)x=-x;return x;
}
struct node{
	int ls,rs,w,siz,a[4],len,al;
	int f[5][5];
}tr[N];
int tot,n,root;
void newnode(int&id,int k,int a,int b,int c){
	id=++tot;
	tr[id].w=rand(),tr[id].siz=1,tr[id].al=tr[id].len=k;
	tr[id].a[1]=a,tr[id].a[2]=b,tr[id].a[3]=c;
	tr[id].f[1][1]=tr[id].a[1]*k;
	tr[id].f[2][2]=tr[id].a[2]*k;
	tr[id].f[3][3]=tr[id].a[3]*k;
	tr[id].f[4][4]=tr[id].a[1]*k;
	for(int i=1;i<=3;i++){
		for(int j=i+1;j<=4;j++){
			tr[id].f[i][j]=max(tr[id].f[i][j-1],tr[id].f[j][j]);
		}
	}
}
void pushup(int p){
	memset(tr[p].f,0,sizeof tr[p].f);
	int ok[5]={};
	int ls=tr[p].ls,rs=tr[p].rs;
	ok[1]=tr[p].f[1][1]=tr[p].a[1]*tr[p].len;
	ok[2]=tr[p].f[2][2]=tr[p].a[2]*tr[p].len;
	ok[3]=tr[p].f[3][3]=tr[p].a[3]*tr[p].len;
	ok[4]=tr[p].f[4][4]=tr[p].a[1]*tr[p].len;
	for(int i=1;i<=4;i++)tr[p].f[i][i]+=tr[ls].f[i][i]+tr[rs].f[i][i];
	for(int len=2;len<=4;len++){
		for(int l=1;l+len-1<=4;l++){
			int r=l+len-1;
			for(int i=l;i<=r;i++){
				tr[p].f[l][r]=max(tr[p].f[l][r],tr[ls].f[l][i]+ok[i]+tr[rs].f[i][r]);
			}
		}
	}
	tr[p].siz=tr[ls].siz+tr[rs].siz+1;
	tr[p].al=tr[ls].al+tr[rs].al+tr[p].len;
}
int merge(int x,int y){
	if(!x||!y)return x|y;
	if(tr[x].w<tr[y].w){
		tr[x].rs=merge(tr[x].rs,y);
		pushup(x);
		return x;
	}
	tr[y].ls=merge(x,tr[y].ls);
	pushup(y);
	return y; 

}
void split(int id,int cnt,int&x,int&y){
	if(!id){
		x=y=0;
		return;
	}
	if(tr[tr[id].ls].al+tr[id].len<cnt){
		x=id;
		split(tr[id].rs,cnt-(tr[tr[id].ls].al+tr[id].len),tr[x].rs,y);
		pushup(x);
	}
	else{
		y=id;
		split(tr[y].ls,cnt,x,tr[y].ls);
		pushup(y);
	}
}
void split2(int id,int k,int&x,int &y){
	if(!id){
		x=y=0;
		return;
	}
	if(tr[tr[id].ls].siz+1<=k){
		x=id;
		split2(tr[id].rs,k-tr[tr[id].ls].siz-1,tr[x].rs,y);
		pushup(x);
	}
	else{
		y=id;
		split2(tr[y].ls,k,x,tr[y].ls);
		pushup(y);
	}
}
signed main(){ 
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	srand(time(0));
	cin>>n;
	int lst=0;
	while(n--){
		int p,a,b,c,x;
		cin>>p>>a>>b>>c>>x;
		int T1,T2,T3;
		split(root,p,T1,T2);
		if(tr[T1].al!=p){
			split2(T2,1,T3,T2);
			int a=tr[T3].a[1],b=tr[T3].a[2],c=tr[T3].a[3],len=tr[T3].len;
			int x,xx;
			newnode(x,p-tr[T1].al,a,b,c);
			newnode(xx,len-(p-tr[T1].al),a,b,c);
			T1=merge(T1,x),T2=merge(xx,T2);
		}
		int t;newnode(t,x,a,b,c);
		root=merge(merge(T1,t),T2);
		int ans=tr[root].f[1][4];
		cout<<ans-lst<<'\n';
		lst=ans;
	}
	return 0;
}

本文作者:Xdik

本文链接:https://www.cnblogs.com/Xdik/p/18709451

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Xdik  阅读(6)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起