首页 > 其他分享 >P10120『STA - R4』冰红茶 题解

P10120『STA - R4』冰红茶 题解

时间:2024-03-07 13:58:38浏览次数:31  
标签:冰红茶 P10120 题解 干掉 ch auto 区间 DS define

分析

出得很好,模板套模板,希望下次再来。

难点在于维护最后连续喝的 DS 饮料数量。设这次喝原味饮料的区间为 \([l,r]\),上一次为 \([l',r']\)。则有两种情况:

  1. \([l,r]\) 与 \([l',r']\) 不相交。如:

在 \([l',r']\) 和 \([l,r]\) 两个区间中的 DS 连续喝的同种饮料数量都会变成 \(k\),而其他的则增加 \(k\)。

  1. \([l,r]\) 与 \([l',r']\) 相交。如:

在 \([l',r']\) 和 \([l,r]\) 两个区间中不相交的区间的 DS 连续喝的同种饮料数量都会变成 \(k\),而其他的则增加 \(k\)。

这就是操作一转化之后你能维护的东西。说是模板其实是因为这个区间赋值和区间加就是扶苏的问题。这里就不分析了。

然后就是另一个模板——维护操作二。很明显的一个小清新,因为 DS 的数量不增。考虑线段树上的某个区间在什么情况下会有 DS 被干掉。因为 BTC 是干掉连续喝相同饮料数量不少于 \(k\) 的,所以维护一个区间最大值,若最大值 \(x \ge k\) 且该区间有 DS 没被干掉时,这个区间有很大可能发生 DS 被 BTC 干掉的情况。很简单的模板小清新,单点修改即可。

对于询问,就是求出来区间 \([1,n]\) 有多少 DS 被干掉了,答案为 \(n-cnt\)。求序列被干掉的 DS 数量可以 \(O(1)\)。

复杂度 \(O(n \log n)\)。

小细节:保证小清新的时间复杂度,当一个 DS 被干掉之后,他的最大值应赋值为极小值。

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define re register
#define il inline
#define pii pair<int,int>
#define x first
#define y second
#define gc getchar()
#define rd read()
#define debug() puts("------------")

namespace yzqwq{
	il int read(){
		int x=0,f=1;char ch=gc;
		while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc;}
		while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=gc;
		return x*f;
	}
	il int qmi(int a,int b,int p){
		int ans=1;
		while(b){
			if(b&1) ans=ans*a%p;
			a=a*a%p,b>>=1;
		}
		return ans;
	}
	il auto max(auto a,auto b){return (a>b?a:b);}
	il auto min(auto a,auto b){return (a<b?a:b);}
	il int gcd(int a,int b){
		if(!b) return a;
		return gcd(b,a%b);
	}
	il int lcm(int a,int b){
		return a/gcd(a,b)*b;
	}
	il void exgcd(int a,int b,int &x,int &y){
		if(!b) return x=1,y=0,void(0);
		exgcd(b,a%b,x,y);
		int t=x;
		x=y,y=t-a/b*x;
		return ;
	}
	mt19937 rnd(time(0));
}
using namespace yzqwq;

const int N=3e5+10;
int n,q;
pii lst;
struct Tree{
	int l,r;
	int mx,kil;
	int tag1,tag2,tag;
}tr[N<<2];

il void up(int now){
	tr[now].mx=max(tr[now<<1].mx,tr[now<<1|1].mx);
	tr[now].kil=tr[now<<1].kil+tr[now<<1|1].kil;
	return ;
}
il void down(int now){
	if(tr[now].tag==1){//覆盖 
		tr[now<<1].tag1=tr[now<<1|1].tag1=tr[now].tag1;
		tr[now<<1].tag2=tr[now<<1|1].tag2=tr[now].tag2;
		tr[now<<1].mx=tr[now<<1|1].mx=tr[now].tag1+tr[now].tag2;
		tr[now].tag1=tr[now].tag2=tr[now].tag=0;
		tr[now<<1].tag=tr[now<<1|1].tag=1; 
	}
	else{//加
		tr[now<<1].tag2+=tr[now].tag2,
		tr[now<<1|1].tag2+=tr[now].tag2;
		tr[now<<1].mx+=tr[now].tag2,
		tr[now<<1|1].mx+=tr[now].tag2;
		tr[now].tag1=tr[now].tag2=tr[now].tag=0;
	}
	return ;
}
il void build(int now,int l,int r){
	tr[now].l=l,tr[now].r=r;
	if(l==r) return ;
	int mid=l+r>>1;
	build(now<<1,l,mid),build(now<<1|1,mid+1,r);
	return ;
}
il void add1(int now,int l,int r,int k){//区间加
	if(tr[now].l>=l&&tr[now].r<=r){
		tr[now].mx+=k,
		tr[now].tag2+=k;
		return ;
	}
	down(now);
	int mid=tr[now].l+tr[now].r>>1;
	if(l<=mid) add1(now<<1,l,r,k);
	if(mid<r) add1(now<<1|1,l,r,k);
	return up(now),void(0);
}
il void add2(int now,int l,int r,int k){//区间覆盖
	if(tr[now].l>=l&&tr[now].r<=r){
		tr[now].mx=tr[now].tag1=k,
		tr[now].tag2=0,tr[now].tag=1;
		return ;
	}
	down(now);
	int mid=tr[now].l+tr[now].r>>1;
	if(l<=mid) add2(now<<1,l,r,k);
	if(mid<r) add2(now<<1|1,l,r,k);
	return up(now),void(0);
}
il void del(int now,int l,int r,int k){//干掉 DS
	if(tr[now].l==tr[now].r){
		tr[now].mx=-1e18,tr[now].kil=1;
		return ;
	}
	down(now);
	int mid=tr[now].l+tr[now].r>>1;
	if(l<=mid&&tr[now<<1].mx>=k&&tr[now<<1].kil<tr[now<<1].r-tr[now<<1].l+1) del(now<<1,l,r,k);
	if(mid<r&&tr[now<<1|1].mx>=k&&tr[now<<1|1].kil<tr[now<<1|1].r-tr[now<<1|1].l+1) del(now<<1|1,l,r,k);
	return up(now),void(0);
}

il void solve(){
	n=rd,q=rd;
	build(1,1,n);
	for(re int i=1;i<=q;++i){
		int op=rd,l,r,k;
		if(op==1){
			l=rd,r=rd,k=rd;
			if(!lst.x) add1(1,1,n,k),lst={l,r};
			else{
				int l_=lst.x,r_=lst.y;
				if(r_<l||r<l_){//区间不相交 
					if(min(l,l_)>1) add1(1,1,min(l,l_)-1,k);
					if(max(r,r_)<n) add1(1,max(r,r_)+1,n,k);
					add2(1,l_,r_,k);
					add2(1,l,r,k);
					if(r_<l&&r_+1<=l-1) add1(1,r_+1,l-1,k);
					if(r<l_&&r+1<=l_-1) add1(1,r+1,l_-1,k);
				}
				else{//区间相交 
					if(min(l,l_)>1) add1(1,1,min(l,l_)-1,k);
					if(max(r,r_)<n) add1(1,max(r,r_)+1,n,k);
					add2(1,min(l,l_),max(l,l_)-1,k);
					add2(1,min(r,r_)+1,max(r,r_),k);
					add1(1,max(l,l_),min(r,r_),k);
				}
				lst={l,r};
			}
		}
		else if(op==2){
			l=rd,r=rd,k=rd;
			del(1,l,r,k);
		}
		else printf("%lld\n",n-tr[1].kil);
	}
	return ;
}

signed main(){
	int t=1;while(t--)
	solve();
	return 0;
}

标签:冰红茶,P10120,题解,干掉,ch,auto,区间,DS,define
From: https://www.cnblogs.com/harmisyz/p/18058740

相关文章

  • AT_abc343_f [ABC343F] Second Largest Query 题解
    分析考虑乱搞。对于求次大值,用线段树维护就行了。记录下每个区间的最大、次大值。则两个子区间的父区间的最大值就是这四个最大的,次大值就是这四个次大的。复杂度\(O(\logn)\)。求次大值的出现次数,乱搞就行了。因为带修,带修莫队或者分块有些麻烦。其实用线段树就行。在维护区......
  • P8058 [BalkanOI2003] Farey 序列 题解
    分析考虑二分答案。对于当前二分的答案\(x\),设\(cnt\)表示Farey序列中\(\frac{p}{q}\lex\)的满足条件的数量。对于一组\((i,j)\),若\(\frac{j}{i}\lex\),则\(j\le\lfloori\timesx\rfloor\)。得到暴力式子:\[cnt=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{\lfloo......
  • P9989 [Ynoi Easy Round 2023] TEST_69 题解
    分析考虑线段树。\(20\)分统计节点懒标记,在每次询问之前统一下传\((lst,i-1)\)的修改懒标记,\(lst\)是上一次询问的位置。\(40\)分在统一下传的过程中打标记,如果当前节点的某个儿子所在子树中没有需要下传懒标记的节点,则不更新那个儿子的内容。\(70\)分注意到\(a\)......
  • CF1915G Bicycles 题解
    分析参照去年普及组T4,很显然能发现就是一个暴力最短路。设\(dis_{i,j}\)表示从\(1\)走到\(i\)且能得到的\(s\)最小为\(j\)时的最短路。那么答案就是\(\min\{dis_{n,i}|1\lei\leV\}\)。考虑最短路转移。对于当前的\(dis_{u,j}\),走到\(v\)的代价将会是\(w_{u......
  • AT_abc252_g [ABC252G] Pre-Order 题解
    分析考虑区间DP。定义状态函数\(\mathit{f}_{l,r,1/0}\)表示在\(P_l,P_{l+1},\dots,P_r\)这些点中,\(P_l\)是或不是唯一(子)树根时的答案。对于\(\mathit{f}_{l,r,1}\),\(P_l\)的第一个儿子一定是\(P_{l+1}\)。所以有:\(f_{l,r,1}=f_{l+1,r,1/0}\)(\(P_{l+1}\)是或不是\(P......
  • AT_abc338_f [ABC338F] Negative Traveling Salesman 题解
    分析考虑状压。定义状态函数\(f_{i,j}\)表示在经过点的情况为\(i\)且最后停在点\(j\)的最小花费。那有:\(f_{i,j}=\min\{f_{i',k}+w_{k\toj}|k\toj\}\)。然后就过不了样例一。根据样例一,可以发现\(f_{3,2}=f_{2,2}+w_{2\to1}+w_{1\to2}\)。也就是说我们在原本已经走......
  • P4958 [COCI2017-2018#6] Mate 题解
    分析考虑DP。先考虑\(A\)的答案。定义状态函数\(f_{i,j}\)表示在子串\(S_{1\dotsi}\)中选\(j\)个,且第\(S_i\)必选的方案数。则有:\(f_{i,j}=C_{i-1}^{j-1}\)。再考虑\(B\)的答案。枚举每一个位置\(x\)。令\(sum_x=\sum\limits_{i=1}^{x-1}f_{i,n-1}[S_i=A]\)。......
  • AT_abc283_f [ABC283F] Permutation Distance 题解
    分析分类讨论。对\(|p_i-p_j|+|i-j|\)分类讨论,有:\((p_i+i)-(p_j+j)\),\(p_i>p_j\landi>j\)。\(-(p_i-i)+(p_j-j)\),\(p_i<p_j\landi>j\)。\((p_i-i)-(p_j-j)\),\(p_i>p_j\landi<j\)。\(-(p_i+i)+(p_j+j)\),\(p_i<p_j\landi<j......
  • CF38E Let's Go Rolling! 题解
    分析考虑DP。因为\(n\le3000\),我们可以直接枚举插针的位置。定义状态函数\(f_i\)表示在从左往右第\(i\)个小球的位置上插针的最小花费。枚举该小球右边第一个插针的位置,则\(i\)到\(j-1\)的小球都会滚到小球\(i\)的位置。代价为\(\sum\limits_{k=i}^{j-1}x_k-x_i......
  • P6390 [COCI2007-2008#4] POKLON 题解
    感谢@\(\color{#AEF}{\texttt{CelestialCyan}}\)大神对我的骚扰帮助。分析一眼DP。对于求最大满足条件区间数,我们定义状态函数\(\mathit{f}_{i}\)表示在第\(1\)到\(i\)个区间中选择,且必选第\(i\)个区间能够得到的最大长度。有转移方程:\(\mathit{f}_{i}=\max\{f[j]|......