# P7476 "C.E.L.U-02" bitter

#### Main idea of the title:

There are n repeatable sets, and the initial is empty; Will perform \ (m \) operations;

There are \ (3 \) operations:

1. Add an element \ (k \) to the set of \ (l \) to \ (r \)

2. Delete the largest element in the collection from \ (l \) to \ (r \). If there are multiple largest elements in the collection, only one will be deleted. If there are no elements in the collection from \ (l \) to \ (r \), it will be ignored

3. Query the largest element in the \ (l \) to \ (r \) sets. If there are no elements in the \ (l \) to \ (r \) sets, output \ (- 1 \)

It is required to output the answers of all query operations.

##### Algorithm 1: violent modification query

Maintain \ (n \) \ (multiset \), traverse the set from \ (l \) to \ (r \) each time, and modify + query violently.

Time complexity: \ (O(nm) \), expected score: \ (10pts \)

##### Algorithm 2: special property A

For \ (subtask2 \), the problem becomes that the interval is assigned a large value and the interval is checked for the maximum value.

The maintenance interval of segment tree is the largest, time complexity: \ (O(n\log{n}) \), expected score: \ (20pts \)

##### Algorithm 3: special property B method 1

For \ (subtask3,5 \), the original interval deletion maximum becomes the single point deletion maximum.

Consider blocking, maintain a large root heap in each block and point, and record the maximum value in the block.

When deleting, find the largest block in the interval, traverse a single point in the block, and compare the heap top of the heap in the single point with the heap top in the block,

If the value in a single point is larger, delete it directly and update the maximum value in a single point and block;

Otherwise, each heap in the block will be added to the heap at this point after deletion, and there is no need to update the maximum value.

Time complexity: \ (O(n\sqrt{n}\log{n})), expected score: \ (30pts \)

##### Algorithm 4: special property B method 2

With the idea of large root heap, we can maintain the large root heap at the lowest node of the segment tree and record the maximum value

Every time you delete, search to the bottom. The \ (O(\log{n}) \) modified by \ (O(\log{n}) \) plus the heap is \ (O(\log^2{n}) \)

Time complexity: \ (O(n\log^2{n}) \), expected score: \ (30pts \)

##### Algorithm 5: segment tree + heap

Consider adding \ (pushdown \) operation on the basis of algorithm 4;

The heap is maintained in each segment tree node, and the parent node records the value of each change operation;

When querying, it will be pushed down, and when deleting, it can be directly deleted in the heap of the parent node;

Time complexity: \ (O(n\log^2{n}) \), expected score: \ (60\)~$$100pts$$

##### Algorithm 6: Mark persistence

With the introduction of Algorithm five \ (pushdown \) operation, you can think of mark persistence.

When dropping the modification operation, use the complexity of \ (\ log{n} \) to recursively drop, delete the same, and add the depth complexity \ (O(\log^2{n}) \)

Time complexity: \ (O((n+m)\log^2{n}) \), expected score: \ (100pts \)

### code

#include<bits/stdc++.h>
#define N 200005
#define inf 0x3f3f3f3f
#define endl '\n'
#define lc (p<<1)
#define rc (p<<1|1)
#define debug cerr<<__LINE__<<endl
using namespace std;
int n,m,tmp;
struct node{
int maxn;priority_queue<int>q;
inline void init(){q.emplace(maxn=-1);}//The heap and maximum values are directly initialized to - 1, so there is no need for special judgment during query
}t[N<<2];
inline char gc(){
static const int L=1<<22|1;static char c[L],*a,*b;
}
register int f=1,k=0;
register char c=gc();
while(c!='-'&&(c<'0'||c>'9')) c=gc();
if(c=='-') f=-1,c=gc();
while(c>='0'&&c<='9') k=(k<<3)+(k<<1)+(c^48),c=gc();
return f*k;
}
inline void write(register int x){
if(x<0) x=-x,putchar('-');
if(x>9) write(x/10);
putchar((x%10)|48);
}
inline void build(const int p,const int l,const int r){
t[p].init();if(l==r) return;
const register int mid=((l+r)>>1);
build(lc,l,mid);build(rc,mid+1,r);
}
inline void pushnow(const int p,const int k){t[p].q.emplace(k),t[p].maxn=max(t[p].maxn,k);}//Modify current node
inline void pushup(const int p){t[p].maxn=max(max(t[lc].maxn,t[rc].maxn),t[p].q.top());}//Pass Max up
inline void pushdown(const int p,const int l,const int r,const int x,const int y,const int k){
if(x<=l&&r<=y) return;//Modify only nodes with coverage beyond x to y
const register int mid=((l+r)>>1);
if(x>mid) pushnow(lc,k),pushdown(rc,mid+1,r,x,y,k);//If the coverage of the current interval is on the left of the target interval, modify the left interval and continue to search the right interval
else if(y<=mid) pushnow(rc,k),pushdown(lc,l,mid,x,y,k);//ditto
else pushdown(lc,l,mid,x,y,k),pushdown(rc,mid+1,r,x,y,k);//Search both sides
return pushup(p);//to flash back
}
inline void update(const int p,const int l,const int r,const int x,const int y,const int k){
if(x<=l&&r<=y) return pushnow(p,k);//If you find a legal range, change it
const register int mid=((l+r)>>1);
if(x<=mid) update(lc,l,mid,x,y,k);
if(y>mid) update(rc,mid+1,r,x,y,k);
return pushup(p);
}
inline void delet(const int p,const int l,const int r,const int x,const int y,const int k){
if(x<=l&&r<=y) if(t[p].maxn<k) return;//Cut out useless search
if(t[p].q.top()==k){//The element to be deleted is within this interval
t[p].q.pop();//to update
pushdown(p,l,r,x,y,k);//Continue searching in this range
return l==r?void(t[p].maxn=t[p].q.top()):pushup(p);//Update the bottom point, backtracking
}
const register int mid=((l+r)>>1);
if(x<=mid) delet(lc,l,mid,x,y,k);
if(y>mid) delet(rc,mid+1,r,x,y,k);
return pushup(p);
}
inline int query(const int p,const int l,const int r,const int x,const int y){
if(x<=l&&r<=y) return t[p].maxn;
const register int mid=((l+r)>>1);
register int ans=t[p].q.top();
if(x<=mid) ans=max(ans,query(lc,l,mid,x,y));
if(y>mid) ans=max(ans,query(rc,mid+1,r,x,y));
return ans;
}
main(void){