题面
题意
要求我们支持两种操作
- 将区间 [ L , R ] [L,R] [L,R]等级为 x x x的龙升级为 x + 1 x+1 x+1
- 求区间 [ L , R ] [L,R] [L,R]等级最高的龙
思路
看到这种改变等级(版本)的,不难想到可持久化数据结构;
再看到区间操作,那就想想主席树怎么搞吧;
首先,类似于区间线段树,每个叶子结点代表一个区间;
在版本 0 0 0的时候,每个位置都存在龙;
对于操作一来说,这里跟我们写的主席树板子不同;
在主席树板子中,每个旧版本往往只是给新版本做一个工具版本,也就是只使用一次(比如最常见的,每插入一个数开一个新版本);
而这题不同,每个版本可能使用多次,因此注意update
函数的写法;
即每一次修改当前版本 i i i,不仅要从 i − 1 i-1 i−1处继承,也要从已经在版本 i i i上改过的地方继承;
对于操作二来说,我们可以二分版本;
找到一个最大的版本且 [ L , R ] [L,R] [L,R]里面存在龙
也就是一个经典的二分答案;
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N = 5e5 + 10;
struct Node{
int lc,rc; //左右儿子
bool have;//是否存在这样的龙
}tr[N<<5];
int cnt;
void push_up(int p){
tr[p].have = tr[tr[p].lc].have || tr[tr[p].rc].have;
}
int build(int l,int r){
int q = ++cnt;
tr[q].have = 1;
if(l == r){
return q;
}
int mid = (l+r) >> 1;
tr[q].lc = build(l,mid);
tr[q].rc = build(mid+1,r);
return q;
}
void update(int p,int &rt,int l,int r,int ql,int qr){
if(l>=ql && r <= qr){
rt = p;
return;
}
int q = ++cnt;
//这里跟每个版本只使用一次的主席树不同
//每个版本可能使用多次,因此要继承本版本已经做过的操作
tr[q] = tr[rt],rt = q;
int mid = (l + r) >> 1;
if(qr<=mid) update(tr[p].lc,tr[q].lc,l,mid,ql,qr);
else if(ql > mid) update(tr[p].rc,tr[q].rc,mid+1,r,ql,qr);
else{
update(tr[p].lc,tr[q].lc,l,mid,ql,mid);
update(tr[p].rc,tr[q].rc,mid+1,r,mid+1,qr);
}
push_up(q);
return;
}
bool query(int p,int l,int r,int ql,int qr){
if(p == 0) return 0;
if(l >= ql && r <= qr) return tr[p].have;
int mid = (l+r) >> 1;
if(qr <= mid) return query(tr[p].lc,l,mid,ql,qr);
else if(ql > mid) return query(tr[p].rc,mid+1,r,ql,qr);
else{
return query(tr[p].lc,l,mid,ql,qr) || query(tr[p].rc,mid+1,r,ql,qr);
}
}
int root[N];
void solve(){
int n,m;
cin >> n >> m;
root[0] = build(1,n);
int op,l,r,k;
for(int i=1;i<=m;++i){
cin >> op >> l >> r;
if(op == 1){
cin >> k;
update(root[k],root[k+1],1,n,l,r);
}
else{
//至多升到i-1级
int L = 0,R = i-1;
while(L < R){
int mid = (L+R+1) >> 1;
//尽可能大
if(query(root[mid],1,n,l,r)){
L = mid;
}
else{
R = mid - 1;
}
}
cout << L << '\n';
}
}
}
int main(){
std::ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
solve();
return 0;
}