首页 > 其他分享 >P6109 [Ynoi2009] rprmq1 题解-猫树+Segment Tree Beats

P6109 [Ynoi2009] rprmq1 题解-猫树+Segment Tree Beats

时间:2023-10-25 20:13:22浏览次数:48  
标签:Ynoi2009 le val int 题解 ll Tree mid leq

20231025

P6109 [Ynoi2009] rprmq1 题解-猫树+Segment Tree Beats

不愧是学长出的题。。。让我更深刻地理解了猫树。

Statement

传送门

有一个 \(n \times n\) 的矩阵 \(a\),初始全是 \(0\),有 \(m\) 次修改操作和 \(q\) 次查询操作,先进行所有修改操作,然后进行所有查询操作。

一次修改操作会给出 \(l_1,l_2,r_1,r_2,x\),代表把所有满足 \(l_1 \le i \le r_1\) 且 \(l_2 \le j \le r_2\) 的 \(a_{i,j}\) 元素加上一个值 \(x\)。

一次查询操作会给出 \(l_1,l_2,r_1,r_2\),代表查询所有满足 \(l_1 \le i \le r_1\) 且 \(l_2 \le j \le r_2\) 的 \(a_{i,j}\) 元素的最大值。

对于 \(100\%\) 的数据,\(1\leq n,m\leq 5\times 10^4\),\(1\leq q \leq 5\times 10^5\),\(1\leq x\leq 2147483647\),\(1\leq l_1\leq r_1\leq n\),\(1\leq l_2\leq r_2\leq n\)。

Solution

首先我们第一步需要想到的:

二维问题可将一维看作时间轴,转化为历史版本问题。

于是我们把一维看作时间轴,那么答案就是问一段时间的历史最大值。

而且历史最大值,我们可以直接用吉司机线段树维护。

考虑如何处理一段时间——用猫树分治!

我们把这些区间挂在猫树上面进行合并即可。

具体来说,我们需要用吉司机线段树维护一个回退操作,

也就是代码里面的 reset,即放弃之前记录的历史最大。

在猫树上面我们先算 \(mid\sim r\) 的区间的答案,

即直接枚举一次,每次询问即可。

这一步完成后回退回去既可以枚举右子树。

而左子树我们用相同的方法处理即可。

这种思路真的好妙!!!

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

const int N=1e6+5;
const ll inf=2e9;
int n,m,Q;
struct node{
  int l,r;
  ll val;
  bool operator <(const node &rhs) const{
    return val<rhs.val;
  }
};
vector<node> a[N];

#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
#define pb push_back

namespace SGT{
  struct sgt{
  	ll mx,hmx,tag1,tag2;
  	int res;
  }tr[N<<2];

  void pu(int p){
  	tr[p].mx=max(tr[lc].mx,tr[rc].mx);
  	tr[p].hmx=max(tr[lc].hmx,tr[rc].hmx);
  }
  
  void change(int p,ll tag1,ll tag2){
  	tr[p].hmx=max(tr[p].hmx,tr[p].mx+tag1);
  	tr[p].mx+=tag2;
  	tr[p].tag1=max(tr[p].tag1,tr[p].tag2+tag1);
  	tr[p].tag2+=tag2;
  }
  
  void reset(int p){
  	change(lc,tr[p].tag1,tr[p].tag2);change(rc,tr[p].tag1,tr[p].tag2);
  	tr[p].tag1=tr[p].tag2=0;
  	tr[p].hmx=tr[p].mx;tr[p].res=1;
  }
  
  void pd(int p){
  	if(!p) return;
  	if(tr[p].res){reset(lc),reset(rc);tr[p].res=0;}
  	change(lc,tr[p].tag1,tr[p].tag2);change(rc,tr[p].tag1,tr[p].tag2);
  	tr[p].tag1=tr[p].tag2=0;
  }
  
  void update(int l,int r,int p,int x,int y,ll val){
  	if(x<=l&&y>=r){change(p,val,val);return;}
	pd(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].hmx;
  	pd(p);
	ll res=-inf;
	if(x<=mid) res=max(res,query(lson,x,y));
	if(y>mid) res=max(res,query(rson,x,y));
	return res;
  }
}

struct ask{
  int l,r,x,y,id;
}b[N];
ll ans[N];
vector<ask> q[N<<2];

bool cmp1(ask a,ask b){return a.r<b.r;}
bool cmp2(ask a,ask b){return a.l>b.l;}

void add(int l,int r,int p,ask val){
  if(val.l<=mid+1&&val.r>=mid){q[p].pb(val);return;}
  if(val.r<=mid) add(lson,val);
  else add(rson,val);
}

void ins(int x,int op){
  if(op==1) for(auto p:a[x]) SGT::update(1,n,1,p.l,p.r,p.val);
  else for(int i=(int)a[x].size()-1;i>=0;i--) SGT::update(1,n,1,a[x][i].l,a[x][i].r,-a[x][i].val);
}

void sol(int l,int r,int p){
  for(int i=l;i<=mid;i++) ins(i,1);
  int cnt=0,nw=1;
  for(auto i:q[p]) b[++cnt]=i;
  sort(b+1,b+cnt+1,cmp1);
  while(nw<=cnt&&b[nw].r==mid) nw++;
  for(int i=mid+1;i<=r;i++){
  	ins(i,1);
  	if(i==mid+1) SGT::reset(1);
  	while(b[nw].r==i&&nw<=cnt) ans[b[nw].id]=max(ans[b[nw].id],SGT::query(1,n,1,b[nw].x,b[nw].y)),nw++;
  }
  for(int i=r;i>=mid+1;i--) ins(i,-1);
  if(l!=r) sol(rson);
  cnt=0;nw=1;
  for(auto i:q[p]) b[++cnt]=i;
  sort(b+1,b+cnt+1,cmp2);
  while(nw<=cnt&&b[nw].l==mid+1) nw++;
  for(int i=mid;i>=l;i--){
  	if(i==mid) SGT::reset(1);
  	while(b[nw].l==i&&nw<=cnt) ans[b[nw].id]=max(ans[b[nw].id],SGT::query(1,n,1,b[nw].x,b[nw].y)),nw++;
    ins(i,-1);
  }
  if(l!=r) sol(lson);
}

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 P6109 [Ynoi2009] rprmq1 猫树+Segment Tree Beats*/ 
  n=read();m=read();Q=read();
  for(int i=1;i<=m;i++){
  	int l=read(),x=read(),r=read(),y=read();ll val=1ll*read();
  	a[l].pb((node){x,y,val});
  	a[r+1].pb((node){x,y,-val});
  }
  for(int i=1;i<=Q;i++){
  	int l=read(),x=read(),r=read(),y=read();
  	add(1,n,1,(ask){l,r,x,y,i});
  }
  for(int i=1;i<=n;i++) sort(a[i].begin(),a[i].end());
  sol(1,n,1);
  for(int i=1;i<=Q;i++) print(ans[i]);
  return 0; 
}

Conclusion

二维问题可将一维看作时间轴,转化为历史版本问题。

区间离线问题可以考虑用猫树。

标签:Ynoi2009,le,val,int,题解,ll,Tree,mid,leq
From: https://www.cnblogs.com/hwy0622/p/P6109.html

相关文章

  • 75th 2023/10/6 k-D Tree
    附上一图:按维度分级,每次轮换用哪个维度即可oi中大多为2维这就是我对它的全部理解了结构与线段树几乎相同分左右结点时取当前区间段的中位数因而每一个节点都不同于线段树的表示范围它表示的是一个确确实实的节点的值访问前可以维护一个节点及它的子树的维度上下界以减少询......
  • P5156 [USACO18DEC] Sort It Out P 题解
    题意有一个长度为\(n\)的排列\(a_1,a_2,\cdots,a_n\),选出\(\{1,2,\cdots,n\}\)的一个子集,对这个子集中的数依次进行如下操作:设当前数为\(v\),则若\(a_v\)大于\(a_{v+1}\)(如果有的话),就交换。如果小于,则若\(a_v<a_{v-1}\)(如果有的话),就交换。重复上述操作知道\(a_{v-1}<......
  • CF1555D题解
    分析注意到字符集大小很小,那么很容易就会产生回文,那么合法序列的种类就会比较有限。思考对于不同长度而言合法序列的种类,显然长度为\(1\)时无回文,长度为\(2\)只要两个字符不同就无回文。尝试扩展到长度为\(3\)时的情况,显然\(s_1\neqs_2\),\(s_2\neqs_3\)。发现\(s......
  • P9669 [ICPC2022 Jinan R] DFS Order 2 题解
    P9669[ICPC2022JinanR]DFSOrder2题解简要题意给定一棵\(n\)个节点的树,根节点是\(1\)。从根节点开始深度优先搜索这一棵树,dfs序是在搜索过程中访问节点的顺序。对于每一个节点\(v\),你要给出有多少种不同的dfs序,使得\(v\)出现在第\(j\)个位置。答案对\(99824......
  • P9769 HUSTFC 2023 简单的加法乘法计算题 题解
    动态规划#单调队列Question给出一个\(x=0\)通过一些操作把\(x\)变成\(y\)。有两个集合\(A,B\)。\(A\)包含了\(n\)个元素,分别是\(1-n\)的所有正整数,集合\(B\)给出\(m\)个元素,可以进行一下函数选择\(A\)中的一个元素\(a\),令\(x\)加上\(a\)选择\(B\)......
  • CF1555B题解
    分析放桌子有两种放法,一种是上下放,一种是左右放,分别计算最小值取\(\min\)即可。注意到原题使用的是平面直角坐标系,于是将原图顺时针旋转\(90^{\circ}\),将下标表示方式与代码中下标的表示方式统一,相应的,左下角和右上角也变成了左上角和右下角。代码#include<iostream......
  • Kettle链接SqlServer+Jdk8 问题解决
     这两天要弄个ldap对接,客户端server2016,数据库那边winserver2008,数据库也是2008最开是链接出现类似这样的,更换了链接mssql的Jar版本,从12换到了6的老版本,没用。  后来更改网上提示的  C:\ProgramFiles\Java\jre-1.8\lib\security\java.security文件jdk.tls.......
  • B1024 题解
    本着10月杂题题解只记重量级的原则,再加上这个系列好久没更新了,搞一发。原题链接发挥还可以的一场,至少比csp-s发挥的好。T1智慧概率题,考场差点出来,30pts。T2简单计数题,之前几场都卡T2,终于出来一次,100pts。T3简单数据结构题,打的30pts暴力,但是有50pts。T4智慧......
  • CF1572F Stations 题解-Segment Tree Beats
    20231025CF1572FStations题解-SegmentTreeBeats吉司机线段树好题!!!CF3400。传送门Statement有\(n\)个广播站,第\(i\)个广播站高度为\(h_i\),范围为\(w_i\)。初始\(h_i=0,w_i=i\)。广播站\(i\)能向广播站\(j\)传递消息,当且仅当\(i\lej\lew_i\),且\(h_i>\max\lim......
  • 恨7不成妻题解
    恨7不成妻题解分析数位\(DP\)考虑题目中的两个条件,每一位不等于\(7\)直接枚举时把\(7\)排除,其他两种情况直接放在状态里。因为题目要求平方和,我们考虑每次加上一位(设加入的是第\(i\)位)时会发生什么设原平方和为\[\sum_{k=1}^ta_k^2\]加入一位\(p\)之后每个数......