从这里开始
自闭记
自闭的丢人组选手不配拥有游记。
- 打到一半看到 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" << '
';
} else {
cout << "yes" << '
';
}
}
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" << '
';
} else {
cout << "yes" << '
';
}
}
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} ight) ^{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 << '
';
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
", 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 != '
' && 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] << '
';
}
}
return 0;
}