UOJ #515. 【UR #19】前进四 吉司机线段树
每个点若是能造成贡献,必然是从当前节点开始往后走的唯一最小值,所以考虑离线倒着做,吉司机线段树维护时间,取min成功就加1。
#include <iostream>
#include <cstring>
#include <iomanip>
#include <algorithm>
#include <stack>
#include <queue>
#include <numeric>
#include <cassert>
#include <bitset>
#include <cstdio>
#include <vector>
#include <unordered_set>
#include <cmath>
#include <map>
#include <unordered_map>
#include <set>
#include <deque>
#include <tuple>
#define all(a) a.begin(), a.end()
#define cnt0(x) __builtin_ctz(x)
#define endl '\n'
#define ll long long
#define ull unsigned long long
#define cntone(x) __builtin_popcount(x)
#define db double
#define fs first
#define se second
#define AC main(void)
#define ls(u) u << 1
#define rs(u) u << 1 | 1
#define lc u << 1
#define rc u << 1 | 1
#define HYS std::ios::sync_with_stdio(false);std::cin.tie(0);std::cout.tie(0);
const long double eps = 1e-9;
int MOD = 571373;
const int LO = 1 << 20 | 1;
char buffer[LO],*S,*TT;
#define getchar() ((S==TT&&(TT=(S=buffer)+fread(buffer,1,LO,stdin),S==TT))?EOF:*S++)
namespace Fio {
inline std::string sread() {
std::string s = " ";
char e = getchar();
while (!isdigit(e) && !isalpha(e) && e != '*') e = getchar();
while (isdigit(e) || isalpha(e) || e == '*') s += e, e = getchar();
return s;
}
inline int read() {
int x = 0, y = 1;
char c = getchar();
while (!isdigit(c)) {
if (c == '-') y = -1;
c = getchar();
}
while (isdigit(c)) {
x = (x << 3) + (x << 1) + (c ^ 48);
c = getchar();
}
return x *= y;
}
inline ll readll() {
ll x = 0, y = 1;
char c = getchar();
while (!isdigit(c)) {
if (c == '-') y = -1;
c = getchar();
}
while (isdigit(c)) {
x = (x << 3) + (x << 1) + (c ^ 48);
c = getchar();
}
return x *= y;
}
inline void write(ll x) {
if (x < 0) x = -x, putchar('-');
ll sta[35], top = 0;
do sta[top++] = x % 10, x /= 10;
while (x);
while (top) putchar(sta[--top] + '0');
putchar('\n');
}
inline void write(int x) {
if (x < 0) x = -x, putchar('-');
int sta[35], top = 0;
do sta[top++] = x % 10, x /= 10;
while (x);
while (top) putchar(sta[--top] + '0');
putchar('\n');
}
} using namespace Fio;
const int N = 1e6 + 10;
const int INF = 0x3f3f3f3f;
int min(int a, int b) {return a > b ? b : a;}
int max(int a, int b) {return a > b ? a : b;}
int n , m, _;
int d1[] = {0, 0, 1, -1};
int d2[] = {1, -1, 0, 0};
struct Node{
int l, r;
int mx, mx2, cnt;
int tag = -1;
}tr[N << 2];
inline void pushup(int u){
if(tr[lc].mx == tr[rc].mx){
tr[u].mx = tr[rc].mx;
tr[u].mx2 = max(tr[lc].mx2, tr[rc].mx2);
}else if(tr[lc].mx > tr[rc].mx){
tr[u].mx = tr[lc].mx;
tr[u].mx2 = max(tr[lc].mx2, tr[rc].mx);
}else{
tr[u].mx = tr[rc].mx;
tr[u].mx2 = max(tr[rc].mx2, tr[lc].mx);
}
}
inline void build(int u, int l, int r){
tr[u] = {l, r};
tr[u].tag = -1;
if(l == r){
tr[u].mx = INF;
tr[u].mx2 = -INF;
return ;
}
int mid = l + r >> 1;
build(lc, l, mid);
build(rc, mid + 1, r);
pushup(u);
}
inline void pushdown(int u){
if(tr[u].mx < tr[lc].mx){
tr[lc].mx = tr[u].mx;
tr[lc].cnt += tr[u].cnt;
}
if(tr[u].mx < tr[rc].mx){
tr[rc].mx = tr[u].mx;
tr[rc].cnt += tr[u].cnt;
}
tr[u].cnt = 0;
}
inline void modify(int u, int l, int r, int x){
if(tr[u].mx <= x) return ;
if(tr[u].l >= l && tr[u].r <= r && tr[u].mx2 < x){
tr[u].mx = x;
tr[u].cnt ++;
return ;
}
pushdown(u);
int mid = tr[lc].r;
if(l <= mid) modify(u << 1, l, r, x);
if(r > mid) modify(u << 1 | 1, l, r, x);
pushup(u);
}
inline int query(int u, int x){
if(tr[u].l == tr[u].r) return tr[u].cnt;
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if(x <= mid) return query(u << 1, x);
return query(u << 1 | 1, x);
}
struct node{
int tm, v;
int nxt;
}a[N << 1];
int last[N << 1], pre[N << 1], ans[N];
inline void solve(){
n = read(), m = read();
for(int i = 1; i <= n; i ++){
int x = read();
a[i] = node{0, x, 0};
last[i] = i;
}
int cnt = 0;
for(int i = 1; i <= m; i ++){
int op = read();
if(op == 1){
int x = read(), v = read();
a[last[x]].nxt = i + n;
last[x] = i + n;
a[i + n] = {i, v, 0};
}else{
int x = read();
a[i + n] = {i, ++cnt, pre[x]};
pre[x] = i + n;
}
}
build(1, 0, m);
for(int i = n; i; i --){
for(int j = i; j; j = a[j].nxt)
modify(1, a[j].tm, (a[j].nxt ? a[a[j].nxt].tm - 1 : m), a[j].v);
for(int j = pre[i]; j; j = a[j].nxt)
ans[a[j].v] = query(1, a[j].tm);
}
for(int i = 1; i <= cnt; i ++) write(ans[i]);
}
int main(){
_ = 1;
//_ = read();
while(_ --)
solve();
return 0;
}