luogu 4198 楼房重建 线段树维护上升序列

版权声明:_ https://blog.csdn.net/lunch__/article/details/82890800

题意

  • 给你一个区间,支持单点修改,询问整个区间的上升序列,这里的上升序列意思是一遇到比当前最大值大的就把它加在最大值后面。

那个 s t r i n g string 完全不想改,所以做了下 l u o g u luogu 任务计划

y l s o i ylsoi b l o g blog 是真的写得好,果然是 A K k i n g AK_{king}

这里的操作可以用线段树完成

我们维护区间最大值和区间的上升序列

发现修改很简单 难点在于 p u s h u p pushup

我们来讨论一下

如果右区间的左子区间最大值小于左区间最大值

那么右区间的左子区间是没贡献的

直接递归右区间的右子区间就好了

如果右区间的左子区间最大值大于左区间最大值

那么我们递归处理右区间的左子区间

又因为右区间是已经处理好的

我们可以 O ( 1 ) O(1) 计算出右子区间大于左子区间最大值的上升序列长度

接在处理好的左区间上就做完了

复杂度 O ( n l o g 2 n ) O(nlog^2n)

Codes

#include<bits/stdc++.h>
#include<bits/extc++.h>

#define file(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout)
#define go(x, i) for(register int i = head[x]; i; i = nxt[i])
#define For(i, a, b) for(register int i = (a), i##_end_ = (b); i <= i##_end_; ++ i)
#define FOR(i, a, b) for(register int i = (a), i##_end_ = (b); i >= i##_end_; -- i)
#define debug(x) cout << #x << " = " << x << endl
#define mem(a, b) memset(a, b, sizeof(a))
#define cpy(a, b) memcpy(a, b, sizeof(a))
#define min(a, b) (a < b ? a : b)
#define max(a, b) (b < a ? a : b)
#define inf (0x3f3f3f3f)
#define INF (1e18)
#define pb push_back
#define mp make_pair
#define x first
#define y second

typedef unsigned long long ull;
typedef unsigned int uint;
typedef long long ll;
typedef std::pair<ll, int> PLI;
typedef std::pair<int, int> PII;
typedef long double ldb;
typedef double db;

namespace IO {
#define getc() ((S_ == T_) && (T_ = (S_ = Ch_) + fread(Ch_, 1, Buffsize, stdin), S_ == T_) ? 0 : *S_ ++)
	const uint Buffsize = 1 << 15, Output = 1 << 23;
	static char Ch_[Buffsize], *S_ = Ch_, *T_ = Ch_;
	static char Out[Output], *nowps = Out;
	inline void flush(){fwrite(Out, 1, nowps - Out, stdout); nowps = Out;}
	template<typename T>inline void read(T &_) {
		_ = 0; static char __; T ___ = 1;
		for(__ = getc(); !isdigit(__); __=getc()) if(__ == '-') ___ = -1;
		for(; isdigit(__); __ = getc()) _ = (_ << 3) + (_ << 1) + (__ ^ 48);
		_ *= ___;
	}
	template<typename T>inline void write(T _, char __ = '\n') {
		if(!_) *nowps ++ = '0';
		if(_ < 0) *nowps ++ = '-', _ = -_;
		static uint sta[111], tp;
		for(tp = 0; _; _ /= 10) sta[++ tp] = _ % 10;
		for(; tp; *nowps ++ = sta[tp --] ^ 48); *nowps ++ = __;
	}
	template<class T>inline bool chkmax(T &_, T __) {return _ < __ ? _ = __, 1 : 0;}
	template<class T>inline bool chkmin(T &_, T __) {return _ > __ ? _ = __, 1 : 0;}
}

using namespace std;
using namespace IO;

const int N = 1e5 + 10;

int n, q;

struct Segment_Tree {
#define ls (bh << 1)
#define rs (ls | 1)
#define mid ((l + r) >> 1)
#define lson ls, l, mid
#define rson rs, mid + 1, r
	db mx[N << 2]; int S[N << 2];

	int find(int bh, int l, int r, db now) {
		int res = 0;
		while(true) {
			if(l == r) return res + (mx[bh] > now);
			if(mx[ls] < now) bh = rs, l = mid + 1;
			else res += S[bh] - S[ls], bh = ls, r = mid;
		}
	}

	void pushup(int bh, int l, int r) {
		mx[bh] = max(mx[ls], mx[rs]);
		S[bh] = S[ls] + find(rson, mx[ls]);
	}

	void update(int bh, int l, int r, int p, db val) {
		if(l == r) mx[bh] = val, S[bh] = 1;
		else {
			if(p <= mid) update(lson, p, val);
			else update(rson, p, val);
			pushup(bh, l, r);
		}
	}
}T;

int main() {
#ifdef ylsakioi
	file("4198");
#endif
	int x, y;
	read(n), read(q);
	while(q --) {
		read(x), read(y);
		T.update(1, 1, n, x, 1.0 * y / x);
		write(T.S[1]);
	}
	return flush(), 0;
}

猜你喜欢

转载自blog.csdn.net/lunch__/article/details/82890800