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;
}

posted @ 2020-04-05 13:44  阿波罗2003  阅读(505)  评论(3编辑  收藏  举报