UOJ Round #19 简要题解
从这里开始
自闭记
自闭的丢人组选手不配拥有游记。
- 打到一半看到 t3 一堆 100,以为全是写的一个 log,比赛结束后,随便点开了若干份代码。今天是愚人节吗?今天不是清明节吗。。。
- 然后以为难度是倒序,打完发现 AB 都是签到。签到失败 * 2,自闭了。
Problem A 清扫银河
你发现操作是两个:
- 选一个环,所有边翻转状态
- 选一个点,翻转周围的状态
第一类操作至多操作 $m$ 次,第二类至多操作一次,所以问题变成判定是否有解。对第一类操作搞一个生成树。于是我们有了 $O(\frac{Tm^3}{64})$ 的优秀做法。
注意到返祖边最多在 3 个地方出现,把环的那一行的返祖边那一位作为主元,消掉剩下两处。
然后变量数就只有树边数了。
然后就有了一个 $O(Tn^3)$ 的辣鸡做法。
upd:做一个树上前缀和就可以 $O(\frac{Tn^3}{64}) $ 辣。
Code
#include <bits/stdc++.h> using namespace std; typedef bool boolean; template <typename T> boolean vmin(T& a, T b) { return (a > b) ? (a = b, true) : (false); } template <typename T> boolean vmax(T& a, T b) { return (a < b) ? (a = b, true) : (false); } template <typename T> T smax(T x) { return x; } template <typename T, typename ...K> T smax(T a, const K &...args) { return max(a, smax(args...)); } template <typename T> T smin(T x) { return x; } template <typename T, typename ...K> T smin(T a, const K &...args) { return min(a, smin(args...)); } // debugging lib #define VN(x) #x #define Vmsg(x) VN(x) << " = " << (x) #define printv(x) cerr << VN(x) << " = " << (x); #define debug(...) fprintf(stderr, __VA_ARGS__); template <typename A, typename B> ostream& operator << (ostream& os, const pair<A, B>& z) { os << "(" << z.first << ", " << z.second << ')'; return os; } template <typename T> ostream& operator << (ostream& os, const vector<T>& a) { boolean isfirst = true; os << "{"; for (auto z : a) { if (!isfirst) { os << ", "; } os << z; isfirst = false; } os << '}'; return os; } #define pii pair<int, int> #define pil pair<int, ll> #define pli pair<ll, int> #define ll long long #define ull unsigned long long const int inf = (signed) (~0u >> 2); const ll llf = (signed ll) (~0ull >> 2); #define pb push_back #define eb emplace_back #define fi first #define sc second template <typename T> int vsize(vector<T>& x) { return (signed) x.size(); } template <typename T> int discrete(T* a, int* b, int n) { vector<T> v(a + 1, a + n + 1); sort(v.begin(), v.end()); v.erase(unique(v.begin(), v.end()), v.end()); for (int i = 1; i <= n; i++) b[i] = lower_bound(v.begin(), v.end(), a[i]) - v.begin() + 1; return v.size(); } mt19937 rng (time(NULL)); int randint(int l, int r) { return rng() % (r - l + 1) + l; } const int N = 305, M = N * N; typedef bitset<N> bit; int T; int n, m; int tid[M]; vector<pii> G[N]; typedef class LinearBasis { public: bit a[N]; bool insert(bit v) { for (int i = n - 1; i--; ) { if (v.test(i)) { v ^= a[i]; } if (v.test(i)) { a[i] = v; return true; } } return false; } void clear() { for (int i = 0; i < n; i++) { a[i].reset(); } } } LinearBasis; int cnte = 0; bit qbit; bit bnear[N]; bitset<N * N> _qbit; bool vis[N]; int fa[N], fae[N], dep[N]; LinearBasis lb; void dfs1(int p, int _fa, int _fae) { fa[p] = _fa; fae[p] = _fae; vis[p] = true; dep[p] = dep[_fa] + 1; if (~_fae) { tid[_fae] = cnte++; } for (auto _ : G[p]) { int e = _.fi; int id = _.sc; if (id == _fae) { continue; } if (!vis[e]) { dfs1(e, p, id); } } } void dfs2(int p) { static bit b; for (auto _ : G[p]) { int e = _.fi; int id = _.sc; if (e == fa[p]) { continue; } if (~tid[id]) { dfs2(e); } else if (dep[e] < dep[p]) { b.reset(); for (int q = p; q ^ e; q = fa[q]) { b.set(tid[fae[q]]); } if (_qbit.test(id)) { _qbit.flip(id); for (int q = p; q ^ e; q = fa[q]) { _qbit.flip(fae[q]); } } bnear[e] ^= b; bnear[p] ^= b; } } } void solve() { cin >> n >> m; cnte = 0; qbit.reset(); _qbit.reset(); fill(tid, tid + m, -1); for (int i = 0, u, v, c; i < m; i++) { cin >> u >> v >> c; if (c == 1) { _qbit.set(i); } G[u].eb(v, i); G[v].eb(u, i); } for (int i = 1; i <= n; i++) { bnear[i].reset(); } for (int i = 1; i <= n; i++) { if (!vis[i]) { dfs1(i, 0, -1); } } for (int i = 1; i <= n; i++) { for (auto e : G[i]) { if (~tid[e.sc]) { bnear[i].set(tid[e.sc]); } } } for (int i = 1; i <= n; i++) { if (!fa[i]) { dfs2(i); } } for (int i = 1; i <= n; i++) { lb.insert(bnear[i]); } for (int i = 0; i < m; i++) { if (_qbit.test(i)) { assert(tid[i] >= 0); qbit.set(tid[i]); } } if (lb.insert(qbit)) { cout << "no" << '\n'; } else { cout << "yes" << '\n'; } } void clear() { fill(vis, vis + n + 1, false); lb.clear(); for (int i = 1; i <= n; i++) { G[i].clear(); } } int main() { ios::sync_with_stdio(false); cin.tie(0), cout.tie(0); cin >> T; while (T--) { solve(); clear(); } return 0; }
考虑所有环的形成空间有什么性质。考虑随便拿一组标为 1 的边集,如果包含某条返祖边就异或上它。最后要在生成树上不剩任何边。不难证明这个条件是初始每个点的度数为偶数。
因此只用让每个点的度数为偶数就行了。变量数只有 $n$ 个了。
时间复杂度 $O(\frac{Tn^3}{64})$。
Code
#include <bits/stdc++.h> using namespace std; typedef bool boolean; template <typename T> boolean vmin(T& a, T b) { return (a > b) ? (a = b, true) : (false); } template <typename T> boolean vmax(T& a, T b) { return (a < b) ? (a = b, true) : (false); } template <typename T> T smax(T x) { return x; } template <typename T, typename ...K> T smax(T a, const K &...args) { return max(a, smax(args...)); } template <typename T> T smin(T x) { return x; } template <typename T, typename ...K> T smin(T a, const K &...args) { return min(a, smin(args...)); } // debugging lib #define VN(x) #x #define Vmsg(x) VN(x) << " = " << (x) #define printv(x) cerr << VN(x) << " = " << (x); #define debug(...) fprintf(stderr, __VA_ARGS__); template <typename A, typename B> ostream& operator << (ostream& os, const pair<A, B>& z) { os << "(" << z.first << ", " << z.second << ')'; return os; } template <typename T> ostream& operator << (ostream& os, const vector<T>& a) { boolean isfirst = true; os << "{"; for (auto z : a) { if (!isfirst) { os << ", "; } os << z; isfirst = false; } os << '}'; return os; } #define pii pair<int, int> #define pil pair<int, ll> #define pli pair<ll, int> #define ll long long #define ull unsigned long long const int inf = (signed) (~0u >> 2); const ll llf = (signed ll) (~0ull >> 2); #define pb push_back #define eb emplace_back #define fi first #define sc second template <typename T> int vsize(vector<T>& x) { return (signed) x.size(); } template <typename T> int discrete(T* a, int* b, int n) { vector<T> v(a + 1, a + n + 1); sort(v.begin(), v.end()); v.erase(unique(v.begin(), v.end()), v.end()); for (int i = 1; i <= n; i++) b[i] = lower_bound(v.begin(), v.end(), a[i]) - v.begin() + 1; return v.size(); } mt19937 rng (time(NULL)); int randint(int l, int r) { return rng() % (r - l + 1) + l; } const int N = 305; typedef bitset<N> bit; int T; int n, m; typedef class LinearBasis { public: bit a[N]; bool insert(bit v) { for (int i = n - 1; i--; ) { if (v.test(i)) { v ^= a[i]; } if (v.test(i)) { a[i] = v; return true; } } return false; } void clear() { for (int i = 0; i < n; i++) { a[i].reset(); } } } LinearBasis; bit G[N], qbit; LinearBasis lb; void solve() { cin >> n >> m; qbit.reset(); for (int i = 0; i < n; i++) { G[i].reset(); } for (int i = 0, u, v, c; i < m; i++) { cin >> u >> v >> c; --u, --v; if (c == 1) { qbit.flip(u); qbit.flip(v); } G[u].flip(u); G[u].flip(v); G[v].flip(u); G[v].flip(v); } for (int i = 0; i < n; i++) { lb.insert(G[i]); } if (lb.insert(qbit)) { cout << "no" << '\n'; } else { cout << "yes" << '\n'; } } int main() { ios::sync_with_stdio(false); cin.tie(0), cout.tie(0); cin >> T; while (T--) { solve(); lb.clear(); } return 0; }
Problem B 通用测评号
20 分做法:写一个四方 dp,然后组合数只预处理到 $n$,rk 6 → rk 18.
不难发现,如果放满了,继续放不会改变答案。
考虑计算 $1$ 未被填满的概率。考虑枚举最后填上的是哪一个。
如果是 $1$,然后容斥计算填最后一个后,剩下哪些还没有填满。
假设一共有 $k$ 个位置没有填满,它们一共填了 $x$ 个,那么每个前后都可以放上一些未被硬点的位置的填东西操作。对于填一处的操作需要乘上 $\frac{1}{1 - \frac{n - k}{n}} = \frac{n}{k}$。所以总共要乘上 $\left(\frac{n}{k} \right) ^{x + 1}$。
如果不是 $1$,假设最后填上的是 $2$,那么枚举一下 $1$ 填了多少个。
剩下是一个背包,暴力实现可以四方,NTT 优化可以三方乘 log。实际上这可以做到三方
问题等价于将 $j$ 个带标号东西分给 $i$ 个带标号的人,每个人拿到的东西少于 $b$ 个问方案数。
考虑枚举物品,每次任意扔给一个人,如果不合法,那么枚举哪些东西是扔给它的 $b$ 个,减去这些方案就行了。
第二部分稍有些不同的在于要求第一个人拿到少于 $a$,显然你可以在 dp 中简单处理一下。
时间复杂度 $O(n^3)$。
Emmm....感觉自己啥都记不到了。
可以发现这个东西实际上是 $F(x) = \sum_{i = 0}^{b - 1} \frac{x^i}{i!}$ 求 $k$ 次幂。考虑 $F'(x) = F(x) - \frac{x^{b - 1}}{(b - 1)!}$。
设 $G(x) = F^k(x)$,对两边求导得 $G'(x) = kF^{k - 1}(x)F'(x) = kG(x) - k \frac{x^{b - 1}}{(b - 1)!}F^{k - 1}(x)$。按位推就行了。
Code
#include <bits/stdc++.h> using namespace std; typedef bool boolean; template <typename T> boolean vmin(T& a, T b) { return (a > b) ? (a = b, true) : (false); } template <typename T> boolean vmax(T& a, T b) { return (a < b) ? (a = b, true) : (false); } template <typename T> T smax(T x) { return x; } template <typename T, typename ...K> T smax(T a, const K &...args) { return max(a, smax(args...)); } template <typename T> T smin(T x) { return x; } template <typename T, typename ...K> T smin(T a, const K &...args) { return min(a, smin(args...)); } // debugging lib #define VN(x) #x #define Vmsg(x) VN(x) << " = " << (x) #define printv(x) cerr << VN(x) << " = " << (x); #define debug(...) fprintf(stderr, __VA_ARGS__); template <typename A, typename B> ostream& operator << (ostream& os, const pair<A, B>& z) { os << "(" << z.first << ", " << z.second << ')'; return os; } template <typename T> ostream& operator << (ostream& os, const vector<T>& a) { boolean isfirst = true; os << "{"; for (auto z : a) { if (!isfirst) { os << ", "; } os << z; isfirst = false; } os << '}'; return os; } #define pii pair<int, int> #define pil pair<int, ll> #define pli pair<ll, int> #define ll long long #define ull unsigned long long const int inf = (signed) (~0u >> 2); const ll llf = (signed ll) (~0ull >> 2); #define pb push_back #define eb emplace_back #define fi first #define sc second template <typename T> int vsize(vector<T>& x) { return (signed) x.size(); } template <typename T> int discrete(T* a, int* b, int n) { vector<T> v(a + 1, a + n + 1); sort(v.begin(), v.end()); v.erase(unique(v.begin(), v.end()), v.end()); for (int i = 1; i <= n; i++) b[i] = lower_bound(v.begin(), v.end(), a[i]) - v.begin() + 1; return v.size(); } mt19937 rng (time(NULL)); int randint(int l, int r) { return rng() % (r - l + 1) + l; } #define ll long long void exgcd(int a, int b, int& x, int& y) { if (!b) { x = 1, y = 0; } else { exgcd(b, a % b, y, x); y -= (a / b) * x; } } int inv(int a, int n) { int x, y; exgcd(a, n, x, y); return (x < 0) ? (x + n) : (x); } const int Mod = 998244353; template <const int Mod = :: Mod> class Z { public: int v; Z() : v(0) { } Z(int x) : v(x){ } Z(ll x) : v(x % Mod) { } friend Z operator + (const Z& a, const Z& b) { int x; return Z(((x = a.v + b.v) >= Mod) ? (x - Mod) : (x)); } friend Z operator - (const Z& a, const Z& b) { int x; return Z(((x = a.v - b.v) < 0) ? (x + Mod) : (x)); } friend Z operator * (const Z& a, const Z& b) { return Z(a.v * 1ll * b.v); } friend Z operator ~(const Z& a) { return inv(a.v, Mod); } friend Z operator - (const Z& a) { return Z(0) - a; } Z& operator += (Z b) { return *this = *this + b; } Z& operator -= (Z b) { return *this = *this - b; } Z& operator *= (Z b) { return *this = *this * b; } friend boolean operator == (const Z& a, const Z& b) { return a.v == b.v; } }; Z<> qpow(Z<> a, int p) { Z<> rt = Z<>(1), pa = a; for ( ; p; p >>= 1, pa = pa * pa) { if (p & 1) { rt = rt * pa; } } return rt; } typedef Z<> Zi; const int N = 255; int n, a, b, m; Zi f[N][N * N]; Zi g[N][N * N]; Zi fac[N * N], _fac[N * N]; Zi comb(int n, int m) { return (n < m) ? 0 : fac[n] * _fac[m] * _fac[n - m]; } void prepare(int n) { fac[0] = 1; for (int i = 1; i <= n; i++) { fac[i] = fac[i - 1] * i; } _fac[n] = ~fac[n]; for (int i = n; i; i--) { _fac[i - 1] = _fac[i] * i; } } void work_f(int n) { int m = n * (b - 1); for (int i = 0; i <= n; i++) { f[i][0] = 1; } for (int j = 1; j <= m; j++) { for (int i = 1; i <= n; i++) { f[i][j] = f[i][j - 1] * i; if (j >= b) { f[i][j] -= f[i - 1][j - b] * i * comb(j - 1, b - 1); } } } } void work_g(int n) { int m = n * (b - 1) + a; for (int i = 0; i <= n; i++) { g[i][0] = 1; } for (int j = 1; j <= m; j++) { for (int i = 0; i <= n; i++) { g[i][j] = g[i][j - 1] * (i + 1); if (j >= a) { g[i][j] -= f[i][j - a] * comb(j - 1, a - 1); } if (j >= b && i) { g[i][j] -= g[i - 1][j - b] * i * comb(j - 1, b - 1); } } } } int main() { ios::sync_with_stdio(false); cin.tie(0), cout.tie(0); cin >> n >> a >> b; m = n * b; if (n == 1) { cout << 0 << '\n'; return 0; } prepare(n * a); Zi invn = ~Zi(n); Zi ans = 0; // last is 1 Zi p = 0; work_f(n - 1); for (int i = 0; i < n; i++) { Zi tmp = 0; Zi v = ~Zi(i + 1), pv = qpow(v, b); for (int s = 0, _ = i * (b - 1); s <= _; s++, pv = pv * v) { int rs = s + b - 1; tmp += f[i][s] * pv * comb(rs, s); } tmp *= comb(n - 1, i); if (i & 1) { p -= tmp; } else { p += tmp; } } ans += p; // last is 2 p = 0; work_g(n - 2); for (int i = 0; i < n - 1; i++) { Zi tmp = 0; Zi v = ~Zi(i + 2), pv = qpow(v, b + b); for (int s = b, _ = i * (b - 1) + a; s <= _; s++, pv *= v) { int rs = s + b - 1; tmp += (g[i][s] - f[i + 1][s]) * pv * fac[rs] * _fac[b - 1] * _fac[s]; } tmp *= comb(n - 2, i); if (i & 1) { p -= tmp; } else { p += tmp; } } ans += p * (n - 1); ans = Zi(n) - ans * n; printf("%d\n", ans.v); return 0; }
Problem C 前进四
考虑从大到小枚举位置,维护每个时间的后缀 min。
这是一个区间取 min 操作。 segment tree beats 维护即可。
Code
#include <bits/stdc++.h> using namespace std; typedef bool boolean; template <typename T> boolean vmin(T& a, T b) { return (a > b) ? (a = b, true) : (false); } template <typename T> boolean vmax(T& a, T b) { return (a < b) ? (a = b, true) : (false); } template <typename T> T smax(T x) { return x; } template <typename T, typename ...K> T smax(T a, const K &...args) { return max(a, smax(args...)); } template <typename T> T smin(T x) { return x; } template <typename T, typename ...K> T smin(T a, const K &...args) { return min(a, smin(args...)); } // debugging lib #define VN(x) #x #define Vmsg(x) VN(x) << " = " << (x) #define printv(x) cerr << VN(x) << " = " << (x); #define debug(...) fprintf(stderr, __VA_ARGS__); template <typename A, typename B> ostream& operator << (ostream& os, const pair<A, B>& z) { os << "(" << z.first << ", " << z.second << ')'; return os; } template <typename T> ostream& operator << (ostream& os, const vector<T>& a) { boolean isfirst = true; os << "{"; for (auto z : a) { if (!isfirst) { os << ", "; } os << z; isfirst = false; } os << '}'; return os; } #define pii pair<int, int> #define pil pair<int, ll> #define pli pair<ll, int> #define ll long long #define ull unsigned long long const int inf = (signed) (~0u >> 2); const ll llf = (signed ll) (~0ull >> 2); #define pb push_back #define eb emplace_back #define fi first #define sc second template <typename T> int vsize(vector<T>& x) { return (signed) x.size(); } template <typename T> int discrete(T* a, int* b, int n) { vector<T> v(a + 1, a + n + 1); sort(v.begin(), v.end()); v.erase(unique(v.begin(), v.end()), v.end()); for (int i = 1; i <= n; i++) b[i] = lower_bound(v.begin(), v.end(), a[i]) - v.begin() + 1; return v.size(); } mt19937 rng (time(NULL)); int randint(int l, int r) { return rng() % (r - l + 1) + l; } #include <bits/stdc++.h> using namespace std; typedef bool boolean; typedef class Input { protected: const static int limit = 65536; FILE* file; int ss, st; char buf[limit]; public: Input() : file(NULL) { }; Input(FILE* file) : file(file) { } void open(FILE *file) { this->file = file; } void open(const char* filename) { file = fopen(filename, "r"); } char pick() { if (ss == st) st = fread(buf, 1, limit, file), ss = 0;//, cerr << "str: " << buf << "ed " << st << endl; return buf[ss++]; } } Input; #define digit(_x) ((_x) >= '0' && (_x) <= '9') Input& operator >> (Input& in, unsigned& u) { char x; while (~(x = in.pick()) && !digit(x)); for (u = x - '0'; ~(x = in.pick()) && digit(x); u = u * 10 + x - '0'); return in; } Input& operator >> (Input& in, unsigned long long& u) { char x; while (~(x = in.pick()) && !digit(x)); for (u = x - '0'; ~(x = in.pick()) && digit(x); u = u * 10 + x - '0'); return in; } Input& operator >> (Input& in, int& u) { char x; while (~(x = in.pick()) && !digit(x) && x != '-'); int aflag = ((x == '-') ? (x = in.pick(), -1) : (1)); for (u = x - '0'; ~(x = in.pick()) && digit(x); u = u * 10 + x - '0'); u *= aflag; return in; } Input& operator >> (Input& in, long long& u) { char x; while (~(x = in.pick()) && !digit(x) && x != '-'); int aflag = ((x == '-') ? (x = in.pick(), -1) : (1)); for (u = x - '0'; ~(x = in.pick()) && digit(x); u = u * 10 + x - '0'); u *= aflag; return in; } Input& operator >> (Input& in, double& u) { char x; while (~(x = in.pick()) && !digit(x) && x != '-'); int aflag = ((x == '-') ? (x = in.pick(), -1) : (1)); for (u = x - '0'; ~(x = in.pick()) && digit(x); u = u * 10 + x - '0'); if (x == '.') { double dec = 1; for ( ; ~(x = in.pick()) && digit(x); u = u + (dec *= 0.1) * (x - '0')); } u *= aflag; return in; } Input& operator >> (Input& in, char* str) { char x; while (~(x = in.pick()) && x != '\n' && x != ' ') *(str++) = x; *str = 0; return in; } Input in (stdin); typedef class Output { protected: const static int Limit = 65536; char *tp, *ed; char buf[Limit]; FILE* file; int precision; void flush() { fwrite(buf, 1, tp - buf, file); fflush(file); tp = buf; } public: Output() { } Output(FILE* file) : tp(buf), ed(buf + Limit), file(file), precision(6) { } Output(const char *str) : tp(buf), ed(buf + Limit), precision(6) { file = fopen(str, "w"); } ~Output() { flush(); } void put(char x) { if (tp == ed) flush(); *(tp++) = x; } int get_precision() { return precision; } void set_percision(int x) { precision = x; } } Output; Output& operator << (Output& out, int x) { static char buf[35]; static char * const lim = buf + 34; if (!x) out.put('0'); else { if (x < 0) out.put('-'), x = -x; char *tp = lim; for ( ; x; *(--tp) = x % 10, x /= 10); for ( ; tp != lim; out.put(*(tp++) + '0')); } return out; } Output& operator << (Output& out, long long x) { static char buf[36]; static char * const lim = buf + 34; if (!x) out.put('0'); else { if (x < 0) out.put('-'), x = -x; char *tp = lim; for ( ; x; *(--tp) = x % 10, x /= 10); for ( ; tp != lim; out.put(*(tp++) + '0')); } return out; } Output& operator << (Output& out, unsigned x) { static char buf[35]; static char * const lim = buf + 34; if (!x) out.put('0'); else { char *tp = lim; for ( ; x; *(--tp) = x % 10, x /= 10); for ( ; tp != lim; out.put(*(tp++) + '0')); } return out; } Output& operator << (Output& out, char x) { out.put(x); return out; } Output& operator << (Output& out, const char* str) { for ( ; *str; out.put(*(str++))); return out; } Output& operator << (Output& out, double x) { int y = x; x -= y; out << y << '.'; for (int i = out.get_precision(); i; i--, y = x * 10, x = x * 10 - y, out.put(y + '0')); return out; } Output out (stdout); const int N = 1e6 + 5; typedef class SegTreeNode { public: int mx, mx2; int tgm, tga; SegTreeNode *l, *r; void upd(int x, int y) { if (x <= mx2) { push_down(); l->upd(x, y); r->upd(x, y); push_up(); } else if (x < mx) { assert(x < tgm); tgm = x; mx = x; tga += y; } } void push_down() { if (tga) { l->upd(tgm, tga); r->upd(tgm, tga); tgm = inf, tga = 0; } } void push_up() { if (l->mx == r->mx) { mx = l->mx; mx2 = max(l->mx2, r->mx2); } else if (l->mx > r->mx) { mx = l->mx; mx2 = max(l->mx2, r->mx); } else { mx = r->mx; mx2 = max(l->mx, r->mx2); } } } SegTreeNode; typedef class SegmentTree { public: static SegTreeNode pool[N << 1]; static SegTreeNode* top; static SegTreeNode* newnode() { top->mx = -inf; top->mx2 = -inf; top->tgm = inf; top->tga = 0; return top++; } int n; SegTreeNode* rt; SegmentTree() : rt(NULL) { } void build(SegTreeNode*& p, int l, int r) { p = newnode(); if (l ^ r) { int mid = (l + r) >> 1; build(p->l, l, mid); build(p->r, mid + 1, r); p->push_up(); } else { p->mx = inf; } } void build(int n) { this->n = n; build(rt, 0, n); } int query(SegTreeNode* p, int l, int r, int idx) { if (l == r) { return p->tga; } p->push_down(); int mid = (l + r) >> 1; if (idx <= mid) return query(p->l, l, mid, idx); return query(p->r, mid + 1, r, idx); } void modify(SegTreeNode* p, int l, int r, int ql, int qr, int v) { if (v >= p->mx) { return; } if (l == ql && r == qr) { p->upd(v, 1); return; } p->push_down(); int mid = (l + r) >> 1; if (qr <= mid) { modify(p->l, l, mid, ql, qr, v); } else if (ql > mid) { modify(p->r, mid + 1, r, ql, qr, v); } else { modify(p->l, l, mid, ql, mid, v); modify(p->r, mid + 1, r, mid + 1, qr, v); } p->push_up(); } int query(int idx) { return query(rt, 0, n, idx); } void modify(int l, int r, int v) { return modify(rt, 0, n, l, r, v); } } SegmentTree; SegTreeNode SegmentTree :: pool[N << 1]; SegTreeNode* SegmentTree :: top = SegmentTree :: pool; typedef class Event { public: int op, p, t, v, tog; Event(int op, int p, int t, int v, int tog) : op(op), p(p), t(t), v(v), tog(tog) { } bool operator < (Event b) const { if (p ^ b.p) { return p > b.p; } if (op ^ b.op) { return op < b.op; } if (t ^ b.t) { return t > b.t; } return tog > b.tog; } } Event; int n, m; int ans[N]; vector<Event> E; SegmentTree st; int main() { in >> n >> m; for (int i = 1, x; i <= n; i++) { in >> x; E.emplace_back(1, i, 0, x, 0); } int qt = 0; for (int i = 1, op, x, y; i <= m; i++) { in >> op >> x; if (op == 1) { in >> y; E.emplace_back(1, x, qt, y, i); } else { E.emplace_back(2, x, qt++, 0, i); } } st.build(qt); sort(E.begin(), E.end()); auto it = E.begin(), _it = E.end(); for (int i = n, ls; i; i--) { ls = qt + 1; while (it != _it && (*it).p == i) { auto& e = *it; if (e.op == 1) { if (e.t ^ ls) { st.modify(e.t, ls - 1, e.v); ls = e.t; } } else { ans[e.t] = st.query(e.t); } it++; } } for (int i = 0; i < qt; i++) { if (~ans[i]) { out << ans[i] << '\n'; } } return 0; }