首页 > 其他分享 >AT_abc256_h [ABC256Ex] I like Query Problem 题解

AT_abc256_h [ABC256Ex] I like Query Problem 题解

时间:2024-03-07 13:22:53浏览次数:14  
标签:le like mathit int 题解 tr 权值 Query now

分析

用势能线段树。

对于一段数字 \(a_l\) 到 \(a_r\),每次全部除以一个大于 \(1\) 的数,不难发现最多除以 \(\log x\) 次就会使 \(a_l\) 到 \(a_r\) 全部变成 \(0\),其中 \(x\) 是区间最大值。

所以,在没有操作 \(2\) 的情况下,我们可以在每次操作 \(1\) 的时候都单点修改,只要在某个需要修改的区间 \([l,r]\) 的和为 \(0\) 时,就不对改区间进行操作。但有了操作 \(2\) 之后,数据是可以在每次操作 \(1\) 之后都加 \(1\) 个操作 \(2\)。这样的时间复杂度就退化成 \(O(nq)\) 了。考虑优化。

我们设区间 \([l,r]\) 的势能函数为 \(\mathit{H}(l,r)\)。若 \([l,r]\) 中的权值均相同,则 \(\mathit{H}(l,r)=1\),否则 \(\mathit{H}(l,r)=\mathit{H}(l,mid)+\mathit{H}(mid+1,r)\)。

在 \([l',r'](l \le l' \le r' \le r)\) 的权值相同的情况下,我们可以直接将 \([l',r']\) 的值全部赋值成 \(\lfloor\frac{v}{x}\rfloor\),这是能做到 \(O(1)\) 的。其中 \(v\) 是该区间的某一个权值,\(x\) 是操作给的值。否则在 \([l',r'](l \le l' \le r' \le r)\) 的权值不相同的情况下,我们就将操作往下推,分成 \([l',mid],[mid+1,r']\)。对单次区间除法操作的复杂度 \(O(\mathit{H}(l',r'))\)。

总的区间除法的复杂度是 \(O(n \log n \log x)\) 的。

注意 \(1\):看 \([l,r]\) 的权值是否相同,直接看区间最大和最小值是否相等就行。

注意 \(2\):区间推平的懒标记初始值是需要赋成 \(-1\) 的,因为存在除法操作之后权值下取整为 \(0\) 的情况。

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define re register
#define il inline

const int N=2e6+10;
int n,q;
struct node{
	int l,r,mi,ma,lz,s;
}tr[N];
int a[N];

il void up(int now){
	tr[now].s=tr[now<<1].s+tr[now<<1|1].s;
	tr[now].ma=max(tr[now<<1].ma,tr[now<<1|1].ma);
	tr[now].mi=min(tr[now<<1].mi,tr[now<<1|1].mi);
	return ;
}
il void down(int now){
	if(tr[now].lz!=-1){
		tr[now<<1].lz=tr[now].lz,tr[now<<1|1].lz=tr[now].lz;
		tr[now<<1].s=(tr[now<<1].r-tr[now<<1].l+1)*tr[now].lz,tr[now<<1|1].s=(tr[now<<1|1].r-tr[now<<1|1].l+1)*tr[now].lz;
		tr[now<<1].ma=tr[now<<1|1].ma=tr[now].ma;
		tr[now<<1|1].mi=tr[now<<1].mi=tr[now].mi;
		tr[now].lz=-1;
	}
	return ;
}
il void build(int now,int l,int r){
	tr[now].l=l,tr[now].r=r,tr[now].lz=-1;
	if(l==r) tr[now].s=tr[now].ma=tr[now].mi=a[l];
	else{
		int mid=l+r>>1;
		build(now<<1,l,mid),build(now<<1|1,mid+1,r);
		up(now);
	}
	return ;
}
il void insert(int now,int l,int r,int x){
	if(tr[now].l>=l&&tr[now].r<=r)
		if(tr[now].ma==tr[now].mi){
			tr[now].ma=tr[now].mi=tr[now].lz=(int)(tr[now].ma/x);
			tr[now].s=(tr[now].r-tr[now].l+1)*tr[now].lz;
			return ;
		}
	down(now);
	int mid=tr[now].l+tr[now].r>>1;	
	if(l<=mid) insert(now<<1,l,r,x);
	if(mid<r) insert(now<<1|1,l,r,x);
	up(now);
	return ;
}
il void insert2(int now,int l,int r,int x){
	if(tr[now].l>=l&&tr[now].r<=r){
		tr[now].ma=tr[now].mi=tr[now].lz=x;
		tr[now].s=(tr[now].r-tr[now].l+1)*tr[now].lz;
	}
	else{
		down(now);
		int mid=tr[now].l+tr[now].r>>1;	
		if(l<=mid) insert2(now<<1,l,r,x);
		if(mid<r) insert2(now<<1|1,l,r,x);
		up(now);
	}
	return ;
}
il int query(int now,int l,int r){
	if(tr[now].l>=l&&tr[now].r<=r) return tr[now].s;
	int ans=0,mid=tr[now].l+tr[now].r>>1;
	down(now);
	if(l<=mid) ans+=query(now<<1,l,r);
	if(mid<r) ans+=query(now<<1|1,l,r);
	up(now);
	return ans;
}

il void solve(){
	cin>>n>>q;
	for(re int i=1;i<=n;++i) cin>>a[i];
	build(1,1,n);
	for(re int i=1,op,l,r,x,y;i<=q;++i){
		cin>>op;
		if(op==1)
			cin>>l>>r>>x,
			insert(1,l,r,x);
		else if(op==2)
			cin>>l>>r>>y,
			insert2(1,l,r,y);
		else
			cin>>l>>r,
			cout<<query(1,l,r)<<"\n";
	}
	return ;
}

signed main(){
	solve();
	return 0;
}

标签:le,like,mathit,int,题解,tr,权值,Query,now
From: https://www.cnblogs.com/harmisyz/p/18058685

相关文章

  • CF1070C Cloud Computing 题解
    分析思路不难想,我们对于第\(i\)个计划的时间,可以分成\(l\)和\(r+1\)两部分。用权值线段树维护,在第\(l\)天的时候就将该计划的内容加入权值线段树中,直到过了该计划的时间,也就是第\(r+1\)天,再将这个计划的内容删除。把每一天需要修改的内容存进vector中,修改完查询权值......
  • AT_dwacon5th_prelims_c k-DMC 题解
    分析先考虑\(k=n\)的情况。对于\(s_j=M\)的时候,其能够匹配的\(s_i=D\)的数量很显然是\(i\lej-1\)的时候的数量,求前缀和就能得到。而对于\(s_j=C\)的时候,能够完整匹配的就是\(i\lej-1\)的时候所有\(s_i=M\)能够匹配的数量之和,再套个前缀和就行了。复杂度是\(O......
  • CF1899G Unusual Entertainment 题解
    分析一眼树上启发式合并。定义\(x_i\)为节点\(i\)在序列\(p\)中的下标。则问题转化为:对于每组\(l,r,k\),询问以\(k\)为根的子树中是否有一个以上的节点,满足\(l\lex_j\ler\)。使用set存以\(i\)为根的子树中\(x_j\)的有序排列。则对于每个\(k=i\)的询问,去合......
  • AT_abc328_f [ABC328F] Good Set Query 题解
    分析考虑并查集。对于\(a_i,b_i,d_i\),若\(a_i,b_i\)在之前的满足要求的操作中,\(a_i,b_i\)不在同一个集合里,则在之前\(X_{a_i},X_{b_i}\)的相对差值是可以任意改变的。令\(k=X_{a_i}-X_{b_i}\),则我们需要将\(a_i\)所在集合中所有元素的值增加\(d_i-k\)。然后将\(a_i,b......
  • CF1895D XOR Construction 题解
    分析对于异或,有性质\(a\oplusb=c,a\oplusc=b,a\oplusa=0\)。则对于\(a_i\oplusa_{i+1}\),其表示的结果就是\(b_{i}\oplusb_{i+2}\)。做一个前缀异或和,就能够得到\(b_1\)与\(b_2,b_3,\dots,b_n\)的异或结果。考虑枚举\(b_1\),因为在有解的情况下\(b_1\op......
  • CF1896D 题解
    Solution令\(l,r\)能使\(\sum\limits_{i=l}^{r}a_i=S\)。考虑先令\(l=1\),那么如果存在\(\sum\limits_{i=1}^{r}=S\),即输出YES。如果没有,则一定有\(\sum\limits_{i=1}^{r}=S-1\),且\(a_{r+1}=2\)。考虑对\(l,r\)进行调整:将\(l\)向左移,\(r\)向右移。可以发现当\(......
  • AT_abc222_f [ABC222F] Expensive Expense 题解
    分析没脑子的题目。一眼换根DP。定义\(\mathit{f}_{i}\)表示\(i\)到\(i\)为根子树中某一个节点的距离最大值;\(\mathit{g}_{i}\)表示\(i\)经过其父节点到某个节点的距离最大值。那答案就是\(\max(\mathit{f}_i,\mathit{g}_i)\)。考虑转移。\(\mathit{f}_i\)的转移很......
  • CF1223F Stack Exterminable Arrays 题解
    分析接着这个说。现在我们需要优化\(\mathit{nxt}_{i}\)。重新定义一下,\(\mathit{nxt}_{i,j}\)表示在后\(i\)个数中,\(j\)第一次出现的位置,且\([i+1,\mathit{nxt}_{i+1,a_i}-1]\)是一个合法串。这玩意很像一个DP,所以完全可以按照DP的转移思路转移:\(\mathit{nxt}_{i,j}=......
  • CF514D R2D2 and Droid Army 题解
    分析乱搞题。考虑将区间\([l,r]\)中所有人干掉的代价。设\(cnt_{i}=\max\limits_{j=l}^{r}a_{j,i}\),则代价为:\(\sum\limits_{i=1}^{m}cnt_i\)。很显然,只有在\(\sum\limits_{i=1}^{m}cnt_i\lek\)是,我们才能将这些人全部干掉。考虑枚举右端点\(r\),与每个\(r\)对应的最......
  • P4863 题解
    Solution为了方便,我们定义\(f_n=\sum_{i=1}^{n}\sum_{j=i}^{n}\lfloor\frac{i}{j}\rfloor\times(-1)^j\)。于是答案即为\(f_b-f_{a-1}\)。观察到如果我们直接计算这个式子而不做丝毫变形的话时间复杂度是\(O(n^2)\)的。考虑把先枚举\(j\),计算\(j\)的贡献。此时就有......