若我们并肩作战,你要照顾好自己哦?|

xingyu_xuan

园龄:1年6个月粉丝:12关注:1

KTT

写课件写着写着开始学 KTT 了是怎么回事。

KTT 解决的基本问题形如,给定 n 个一次函数 kixi+bi,区间对 xi 加正数,查询区间一次函数的值的最大值。

考虑尝试维护每个位置的最大线段交换的阈值 t,即这个位置的儿子两个线段 l1,l2,目前是 l1max,对 xi 再加超过 t 就变成 l2max 了。这个显然在 pushup 的时候要取 min

然后区间加 x 的时候就直接递归到 tx 的节点打上标记就行了,记得把阈值减去 x

可以证明时间复杂度是 O((n+q)log3n) 的,但是因为目前 OI 界还不会卡,所以复杂度可以理解为常数略大一点的 2log。

P5693 EI 的第六分块

给定一个整数序列 a,支持两种操作:

  • 1 l r x 表示给区间 [l,r] 中每个数加上 x
  • 2 l r 表示查询区间 [l,r] 的最大子段和(可以为空)

1n,q4×105|ai|1091x106

如果把区间加变成单点加,我们就可以用正常的线段树来维护最大子段和,我们此时需要维护 (lmx,rmx,ans,sum)

把这四个信息看成一次函数放到 KTT 上,阈值变成 使得任意函数的取值来源变化的最小的 x。合并之类的都是一样正常合并就行了,只需要注意修改的时候递归到合适的位置即可。

合并的时候,加法就是单纯的把真实值和斜率加起来,所以我们不显式维护 xi 的值,而是只维护斜率和真实值。下放标记的时候,不难发现贡献可以直接放到真实值上,因为这里的斜率就是这个信息所对应的区间的长度。

EI 证明了这样做的时间复杂度是 3log 的。

事实上,因为 OI 界目前不会卡这个东西,涉及到 KTT 并且只加正数或者只加负数的标记大概都可以看做是正确的复杂度。

P6792 [SNOI2020] 区间和

有一个长度为 n 的整数数列 a1,a2,,an(可能含有负数)。现在对其进行 q 次操作,每次操作是以下二者之一:

  • 0 l r x 表示对于 [l,r],将 ai 赋值为 max(ai,x)
  • 1 l r 求区间 [l,r] 的最大子段和。即:max(0,maxluvr(i=uvai))

1n105,1q2×105,|ai|,|x|109

加强的疑似有点多了。

首先取 max 部分用 segbeats 做,问题变成区间的所有 min 加上某个正数。

首先显然这两部分是完全独立的计算复杂度的。

注意到如果直接按上面做,这个操作是不能直接贡献到 xi 的。所以我们把斜率维护成 min 值个数(同时注意更新斜率对应的 min 到底是什么),这样就能直接贡献了。虽然没人证,但是普遍认为这样复杂度还是 3log 的。

说实话我是真的不想写这个题代码,太史了,写错一个地方调半年啊。

AT 的某个题

会在课件亮相。是一个 KTT 优化 DP 题,伊娜做过。

板子

最后贴个板子下班。

const int M=5e5+5;
int a[M],pre[M];
int val[M],vcnt;
#define ll long long
#define fi first
#define se second
#define mid ((l+r)>>1)
struct KTT{
	struct line{ll k,b;};
	inline static pair<line,ll> mer(const line &x,const line &y){
		if(x.k==y.k){
			if(x.b>y.b)return {x,1e18};
			else return {y,1e18};
		}
		if(x.k>y.k){
			if(x.b>=y.b)return {x,1e18};
			else return {y,(y.b-x.b)/(x.k-y.k)};
		}
		if(x.b>y.b)return {x,(x.b-y.b)/(y.k-x.k)};
		return {y,1e18};
	}
	struct node{
		line x;ll t;
		inline node operator +(const node &y)const{
			node res;
			auto tmp=mer(x,y.x);
			res.t=min({t,y.t,tmp.se});
			res.x=tmp.fi;
			return res;
		}
	}xds[M<<2];
	ll tg[M<<2],tgb[M<<2];
	inline void pushup(int now){
		xds[now]=xds[now<<1]+xds[now<<1|1];
		return;
	}
	inline void upd(int now,ll w){
		xds[now].t-=w;
		xds[now].x.b+=xds[now].x.k*w;
		tg[now]+=w;
		return;
	}
	inline void add(int now,ll w){
		xds[now].x.b+=w;
		tgb[now]+=w;
		return;
	}
	inline void pushdown(int now){
		if(tg[now]){
			upd(now<<1,tg[now]),upd(now<<1|1,tg[now]);
			tg[now]=0;
		}
		if(tgb[now]){
			add(now<<1,tgb[now]),add(now<<1|1,tgb[now]);
			tgb[now]=0;
		}
		return;
	}
	inline void mdf(int now,int l,int r,int pos,ll v){
		if(l==r){
			xds[now].x.b=max(xds[now].x.b,v);
			return;
		}
		pushdown(now);
		if(pos<=mid)mdf(now<<1,l,mid,pos,v);
		else mdf(now<<1|1,mid+1,r,pos,v);
		return pushup(now);
	}
	inline void add(int now,int l,int r,int sl,int sr,ll w){
		if(sl<=l&&r<=sr)return add(now,w);
		pushdown(now);
		if(sl<=mid)add(now<<1,l,mid,sl,sr,w);
		if(sr>mid)add(now<<1|1,mid+1,r,sl,sr,w);
		return pushup(now);
	}
	inline void upd(int now,int l,int r,ll w){
		if(xds[now].t>=w)return upd(now,w);
		pushdown(now);
		upd(now<<1,l,mid,w),upd(now<<1|1,mid+1,r,w);
		return pushup(now);
	}
	inline void addv(int now,int l,int r,int sl,int sr,ll w){
		if(sl<=l&&r<=sr)return upd(now,l,r,w);
		pushdown(now);
		if(sl<=mid)addv(now<<1,l,mid,sl,sr,w);
		if(sr>mid)addv(now<<1|1,mid+1,r,sl,sr,w);
		return pushup(now);
	}
	inline ll ask(int now,int l,int r,int sl,int sr){
		if(sl<=l&&r<=sr)return xds[now].x.b;
		pushdown(now);
		if(sl>mid)return ask(now<<1|1,mid+1,r,sl,sr);
		if(sr<=mid)return ask(now<<1,l,mid,sl,sr);
		return max(ask(now<<1,l,mid,sl,sr),ask(now<<1|1,mid+1,r,sl,sr));
	}
	inline void build(int now,int l,int r){
		if(l==r){
			xds[now].x.k=val[l];
			xds[now].x.b=-1e18;
			xds[now].t=1e18;
			return;
		}
		build(now<<1,l,mid),build(now<<1|1,mid+1,r);
		return pushup(now);
	}
}T;

本文作者:xingyu_xuan

本文链接:https://www.cnblogs.com/xingyuxuan/p/18619823

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

posted @   xingyu_xuan  阅读(84)  评论(3编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起