首页 > 其他分享 >CF1572F Stations 题解-Segment Tree Beats

CF1572F Stations 题解-Segment Tree Beats

时间:2023-10-25 15:16:03浏览次数:52  
标签:val tag2 Stations int 题解 CF1572F tr mx tag1

20231025

CF1572F Stations 题解-Segment Tree Beats

吉司机线段树好题!!!CF3400。
传送门

Statement

有 \(n\) 个广播站,第 \(i\) 个广播站高度为 \(h_i\),范围为 \(w_i\)。初始 \(h_i=0,w_i=i\)。广播站 \(i\) 能向广播站 \(j\) 传递消息,当且仅当 \(i\le j\le w_i\),且 \(h_i>\max\limits_{k=i+1}^jh_k\)。定义 \(b_i\) 表示能向 \(i\) 传播消息的广播站数量。
接下来有 \(q\) 次操作,分为以下两种类型:

  • 给出 \(i,g\),把 \(h_i\) 变成所有广播站中严格最高的,并且 \(w_i\gets g\)。
  • 给出 \(l,r\),查询 \(\sum_{i=l}^rb_i\)。

\(1\le n,q\le2\times10^5\)。

Solution

看题后感觉毫无思路,

\(b_i\) 是非常难维护的,于是我们考虑先维护 \(w_i\)。

发现每一次变成最高的操作就是对于 \(i\) 单点修改,

再把 \(1 \sim i-1\) 区间内的所有 \(w_i\) 的值与 \(i-1\) 取 \(\min\) ,

这个操作可以直接用吉司机线段树维护。

而再来考虑如何处理 \(b_i\) ,对于每一次修改,

发现我们每次取 \(\min\) 的时候是把 \([i,mx]\) 区间内的 \(b_i\) 减去 \(cnt_{mx}\) ,

于是这个操作可以再用一棵线段树维护即可。

思路非常妙啊,在不好直接维护答案时我们考虑再维护一维。

实现比较简单,也没有什么细节,就差不多时两个模板和一块儿了。

直接一发过了~

#include <bits/stdc++.h>
using namespace std;
#define ll long long

const ll inf=2e9;
const int N=2e5+5;
int n,q;

namespace SGT{
  struct sgt{
  	ll sum,tag;
  }tr[N<<2];
  
  #define mid ((l+r)>>1)
  #define lc p<<1
  #define rc p<<1|1
  #define lson l,mid,lc
  #define rson mid+1,r,rc
  
  void pu(int p){tr[p].sum=tr[lc].sum+tr[rc].sum;}
  
  void pd(int l,int r,int p){
  	if(!tr[p].tag) return; 
  	tr[lc].sum+=1ll*(mid-l+1)*tr[p].tag;
  	tr[rc].sum+=1ll*(r-mid)*tr[p].tag;
  	tr[lc].tag+=tr[p].tag;
  	tr[rc].tag+=tr[p].tag;
  	tr[p].tag=0;
  }
  
  void update(int l,int r,int p,int x,int y,ll val){
  	if(x>y) return;
  	//cout<<"SGT::update:"<<l<<' '<<r<<' '<<p<<' '<<x<<' '<<y<<' '<<val<<endl;
  	if(x<=l&&y>=r){
  	  tr[p].sum+=1ll*(r-l+1)*val;
	  tr[p].tag+=val;
	  return;	
	}
	pd(l,r,p);
	if(x<=mid) update(lson,x,y,val);
	if(y>mid) update(rson,x,y,val);
	pu(p);
  }
  
  ll query(int l,int r,int p,int x,int y){
    if(x<=l&&y>=r) return tr[p].sum;
    pd(l,r,p);
    ll res=0;
    if(x<=mid) res+=query(lson,x,y);
    if(y>mid) res+=query(rson,x,y);
    return res;
  }
  
  void build(int l,int r,int p){
    if(l==r){
      tr[p].sum=1;
      tr[p].tag=0;
      return;
	}
	build(lson);build(rson);
	pu(p);
  } 
  
  #undef mid
  #undef lc
  #undef rc
  #undef lson
  #undef rson
}

namespace STB{
  struct sgt{
    int mx,se,tag1,tag2,cnt;
  }tr[N<<2];
  #define mid ((l+r)>>1)
  #define lson l,mid,p<<1
  #define rson mid+1,r,p<<1|1
  #define lc p<<1
  #define rc p<<1|1
  
  void pu(int p){
  	tr[p].mx=max(tr[lc].mx,tr[rc].mx);
  	if(tr[lc].mx==tr[rc].mx){
  	  tr[p].se=max(tr[lc].se,tr[rc].se);
	  tr[p].cnt=tr[lc].cnt+tr[rc].cnt;	
	}
	else if(tr[lc].mx>tr[rc].mx){
	  tr[p].se=max(tr[lc].se,tr[rc].mx);
	  tr[p].cnt=tr[lc].cnt;
	}
	else{
	  tr[p].se=max(tr[lc].mx,tr[rc].se);
	  tr[p].cnt=tr[rc].cnt;
	}
  }
  
  void change(int p,int tag1,int tag2){
	tr[p].mx+=tag1;
  	tr[p].tag1+=tag1;
  	if(tr[p].se!=-inf) tr[p].se+=tag2;
  	tr[p].tag2+=tag2;
  }
  
  void pd(int p){
    if(!tr[p].tag1&&!tr[p].tag2) return;
    int mx=max(tr[lc].mx,tr[rc].mx);
    if(tr[lc].mx==mx) change(lc,tr[p].tag1,tr[p].tag2);
    else change(lc,tr[p].tag2,tr[p].tag2);
    if(tr[rc].mx==mx) change(rc,tr[p].tag1,tr[p].tag2);
    else change(rc,tr[p].tag2,tr[p].tag2);
    tr[p].tag1=tr[p].tag2=0;
  }
  
  void update(int l,int r,int p,int x,int val){
  	if(l==r){
  	  val=val-tr[p].mx;
  	  if(val>0) SGT::update(1,n,1,tr[p].mx+1,tr[p].mx+val,1);
  	  else SGT::update(1,n,1,tr[p].mx+val+1,tr[p].mx,-1);
  	  tr[p].mx+=val;
	  return;	
	}
	pd(p);
	if(x<=mid) update(lson,x,val);
	else update(rson,x,val);
	pu(p);
  }
  
  void cover(int l,int r,int p,int x,int y,int val){
  	if(l>r||x>y||l>y||r<x||tr[p].mx<=val) return;
  	if(x<=l&&y>=r&&tr[p].mx>val&&tr[p].se<val){
  	  int k=tr[p].mx-val;
	  SGT::update(1,n,1,val+1,tr[p].mx,-tr[p].cnt);
	  tr[p].mx-=k;
	  tr[p].tag1-=k;
	  return;	
	}
	pd(p);
	if(x<=mid) cover(lson,x,y,val);
	if(y>mid) cover(rson,x,y,val);
	pu(p);
  }
  
  void build(int l,int r,int p){
  	if(l==r){
  	  tr[p].mx=l;
	  tr[p].se=-inf;
	  tr[p].tag1=tr[p].tag2=0;
	  tr[p].cnt=1;
	  return;	
	}
	build(lson);build(rson);
	pu(p);
  }
  
  #undef mid
  #undef lson
  #undef rson
  #undef lc
  #undef rc
}

int read(){
  int x=0,f=1;char ch=getchar();
  while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
  while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  return x*f;
}

void print(ll x){
  int p[25],tmp=0;
  if(x==0) putchar('0');
  if(x<0) putchar('-'),x=-x;
  while(x){
  	p[++tmp]=x%10;
  	x/=10;
  }
  for(int i=tmp;i>=1;i--) putchar(p[i]+'0');
  putchar('\n');
}

int main(){
  /*2023.10.25 H_W_Y CF1572F Stations Segment Tree Beats*/
  n=read();q=read();
  STB::build(1,n,1);SGT::build(1,n,1);
  for(int i=1;i<=q;i++){
  	int op=read(),l=read(),r=read();
  	if(op==1){
  	  STB::update(1,n,1,l,r);
	  STB::cover(1,n,1,1,l-1,l-1);	
	}
	else print(SGT::query(1,n,1,l,r));
  }
  return 0;
}

Conclusion

线段树维护时我们可以先考虑如何维护修改,再将询问和修改的关系找到,用两棵线段树维护。

标签:val,tag2,Stations,int,题解,CF1572F,tr,mx,tag1
From: https://www.cnblogs.com/hwy0622/p/CF1572F.html

相关文章

  • 恨7不成妻题解
    恨7不成妻题解分析数位\(DP\)考虑题目中的两个条件,每一位不等于\(7\)直接枚举时把\(7\)排除,其他两种情况直接放在状态里。因为题目要求平方和,我们考虑每次加上一位(设加入的是第\(i\)位)时会发生什么设原平方和为\[\sum_{k=1}^ta_k^2\]加入一位\(p\)之后每个数......
  • P9771 HUSTFC 2023 排列排序问题 题解
    Question给出一个\(N\)个元素的排序\(a\),我们可以对排列进行一些操作将这个排列切割成若干个序列将其中一些序列翻转将这些序列连接起来得到一个新的排列需要让最后的排列有序Solution这个题的描述有点小问题理解应该是切一次,然后再反转合并,不可能会先合并再切再反转......
  • P9744 「KDOI-06-S」消除序列 题解
    @目录DesciptionSolutionCodeDesciption给定一个长度为\(i\)的序列\(v_1,v_2,\dots,v_n\),初始时所有元素的值都为\(1\)。对于下标\(i\)有\(3\)种操作:将\(v_1,v_2,\dots,v_i\)的值变为\(0\),费用是\(a_i\)。将\(v_i\)的值变为\(0\),费用是\(b_i\)。将\(v_i\)......
  • Meta Hacker Cup 2023 Round 1 题解
    ProblemA:HereComesSantaClaus给一个数列,要求分成若干组,要求每组至少2个数,使得所有组中位数的最大值与最小值之差尽量大,求这个值。#include<bits/stdc++.h>usingnamespacestd;#defineFor(i,n)for(inti=1;i<=n;i++)#defineFork(i,k,n)for(inti=k;i<=n;i++)#define......
  • pytest运行警告问题解决:DeprecationWarning: pkg_resources is deprecated as an API
    前言最近在运行pytest的时候,经常出现这个警告DeprecationWarning:pkg_resourcesisdeprecatedasanAPISeehttps://setuptools.pypa.io/en/latest/pkg_resources.htmlfrompkg_resourcesimportiter_entry_points从警告上看是方法被弃用,肯定是因为新版弃用了旧版的语法。遇......
  • szfpga Lattice高速下载器HW-USBN-2B 常见问题解答
      .产品特点     1).支持windows7,Windows10操作系统,两个操作系统非常稳定不断线。  2).支持JTAG模式,速度快,最高30Mb/s,调试serdescore,不会像hw-usbn-2a出现错误。如这种错误Error:failedtosetcablepor(cable:USBport:EzUSB-0error:-1)  3). ......
  • CF1854E Games Bundles 题解
    乱搞题设个\(dp[i]\)表示和为\(i\)的子序列个数,那么转移是容易的,\(dp[j]+=dp[j-i]\),然后就判下\(dp[60]+dp[60-i]\)是否大于\(m\),发现这样子搞对于比较大的数可能达不到\(m\)的限制,因为这样子转移,默认的是一个数只选一次,但是我们可以重复选,这启发我们需要设定一个值......
  • 题解 CF903G【Yet Another Maxflow Problem】
    加边\(A_n\stackrel{0}{\to}A_{n+1}\),\(B_0\stackrel{0}{\to}B_1\)。称形如\(A_i\toA_{i+1}\)的边为左部边,形如\(B_j\toB_{j+1}\)的边为右部边,形如\(A_i\toB_j\)的边为中间边。根据最大流最小割定理,将最大流问题转化为最小割问题求解。显然,至少存在一组最小割,包含恰好......
  • CF1777D题解
    分析首先看到那个\(10^{100}\)再加上样例,我们就能意识到在不是特别多的操作次数后这颗树上的值就会全变成\(0\)。因为没有子节点在一次操作后显然就会变成\(0\),然后第一次叶节点就会变成\(0\),然后下一次子节点中只有叶节点的就会变成\(0\),以此类推,理论上最多操作\(n\)......
  • CF1878B题解
    CF1878BAleksaandStack题目翻译给定\(n\),试构造一个长度为\(n\)的严格上升正整数序列\(a_1,a_2,a_3,...,a_n\)使得\(\foralli\in[3,n],(a_{i-1}+a_{i-2})\nmid3a_i\)。单个测试点内包含多组测试数据。思路拿到题目,发现不好一个数一个数地构造,考虑......