1. 程式人生 > 實用技巧 >Solution -「牛客多校賽 2020 Round II」Happy Triangle

Solution -「牛客多校賽 2020 Round II」Happy Triangle

\(\mathcal{Description}\)

  link.
  維護一個可重集 \(s\),支援:

  1. 插入 \(x\)
  2. 刪除一個 \(x\),保證存在。
  3. 給定 \(x\),詢問是否存在以 \(x\) 以及 \(s\) 中的某兩個元素為三邊長度的三角形。

  操作次數 \(q\le2\times10^5\)

\(\mathcal{Solutioin}\)

  設從集合中取出 \(a,b\),分類討論:

  • \(a\le b\le x\),利用 std::multiset 的一些操作找出 \(x\) 的前驅 \(b\) 以及 \(b\) 的前驅 \(a\),判斷即可。
  • \(a\le x\le b\)
    ,類似,利用 std::multiset
  • \(x\le a\le b\),實際上要求 \(x>b-a\),所以需要維護“大於某個數的元素中與其後綴差的最小值”,可以用平衡樹或者離線下來權值線段樹實現。

  插入和刪除就分別在 std::multiset 和平衡樹中進行修改即可。
  複雜度 \(\mathcal O(q\log q)\)

\(\mathcal{Code}\)

  這裡選用的 Splay 實現平衡樹。注意沒有 cnt 陣列,所以平衡樹不接受重複元素插入。在外部維護時需特別留意,注意 \(s\) 存在重複元素時,該元素與其後綴的差值為 \(0\)

#include <set>
#include <cstdio>

typedef std::multiset<int>::iterator IT;

const int MAXQ = 2e5, INF = 0x3f3f3f3f;
std::multiset<int> s;

inline int min_ ( const int a, const int b ) { return a < b ? a : b; }

inline int rint () {
	int x = 0; char s = getchar ();
	for ( ; s < '0' || '9' < s; s = getchar () );
	for ( ; '0' <= s && s <= '9'; s = getchar () ) x = x * 10 + ( s ^ '0' );
	return x;
}

struct SplayTree {
	int cnt, root, fa[MAXQ + 5], ch[MAXQ + 5][2];
	int key[MAXQ + 5], val[MAXQ + 5], mn[MAXQ + 5];

	inline void pushup ( const int x ) {
		mn[x] = val[x];
		if ( ch[x][0] ) mn[x] = min_ ( mn[x], mn[ch[x][0]] );
		if ( ch[x][1] ) mn[x] = min_ ( mn[x], mn[ch[x][1]] );
	}
	inline void rotate ( const int x ) {
		int y = fa[x], z = fa[y], k = ch[y][1] == x;
		fa[x] = z; if ( z ) ch[z][ch[z][1] == y] = x;
		ch[y][k] = ch[x][k ^ 1]; if ( ch[x][k ^ 1] ) fa[ch[x][k ^ 1]] = y;
		pushup ( ch[fa[y] = x][k ^ 1] = y ), pushup ( x );
	}
	inline void splay ( const int x, const int tar ) {
		for ( int y, z; ( y = fa[x] ) ^ tar; rotate ( x ) ) {
			if ( ( z = fa[y] ) ^ tar ) {
				rotate ( x ^ y ^ ch[y][0] ^ ch[z][0] ? x : y );
			}
		}
		pushup ( x );
		if ( ! tar ) root = x;
	}
	inline void find ( const int x ) {
		int r = root; if ( ! r ) return ;
		for ( ; ch[r][x > key[r]] && x ^ key[r]; r = ch[r][x > key[r]] );
		splay ( r, 0 );
	}
	inline int pre ( const int x ) {
		find ( x ); int r = root;
		if ( key[r] < x ) return r;
		for ( r = ch[r][0]; ch[r][1]; r = ch[r][1] );
		return splay ( r, 0 ), r;
	}
	inline int suf ( const int x ) {
		find ( x ); int r = root;
		if ( key[r] > x ) return r;
		for ( r = ch[r][1]; ch[r][0]; r = ch[r][0] );
		return splay ( r, 0 ), r;
	}
	inline void insert ( const int x, const int v ) {
		int f = 0, r = root;
		for ( ; r && key[r] ^ x; f = r, r = ch[r][x > key[r]] );
		if ( r ) return ;
		r = ++ cnt;
		if ( f ) ch[f][x > key[f]] = r;
		fa[r] = f, key[r] = x, val[r] = v;
		pushup ( r ), splay ( r, 0 );
	}
	inline void erase ( const int x ) {
		int p = pre ( x ), q = suf ( x );
		splay ( p, 0 ), splay ( q, p ), fa[ch[q][0]] = 0, ch[q][0] = 0;
		pushup ( q ), pushup ( p );
	}
} st;

int main () {
	st.insert ( INF, INF ), st.insert ( -INF, INF );
	for ( int q = rint (), op, x; q --; ) {
		op = rint (), x = rint ();
		if ( op == 1 ) {
			if ( s.find ( x ) == s.end () ) {
				IT it = s.upper_bound ( x );
				if ( it != s.end () ) st.insert ( x, *it - x );
				else st.insert ( x, INF );
				if ( it != s.begin () ) {
					-- it;
					if ( s.count ( *it ) == 1 ) st.erase ( *it ), st.insert ( *it, x - *it );
				}
			} else st.erase ( x ), st.insert ( x, 0 );
			s.insert ( x );
		} else if ( op == 2 ) {
			s.erase ( s.find ( x ) );
			if ( s.find ( x ) == s.end () ) {
				st.erase ( x );
				IT tit = s.lower_bound ( x ), it = tit;
				if ( it != s.begin () ) {
					-- it;
					if ( s.count ( *it ) == 1 ) {
						st.erase ( *it );
						if ( tit != s.end () ) st.insert ( *it, *tit - *it );
						else st.insert ( *it, INF );
					}
				}
			} else if ( s.count ( x ) == 1 ) {
				st.erase ( x );
				IT it = s.upper_bound ( x );
				if ( it != s.end () ) st.insert ( x, *it - x );
				else st.insert ( x, INF );
			}
		} else {
			if ( s.size () < 2 ) { puts ( "No" ); continue; }
			if ( s.count ( x ) > 1 ) { puts ( "Yes" ); continue; }
			IT tit = s.lower_bound ( x ), it = tit;
			if ( it == s.end () || ( it != s.begin () && *it > x ) ) -- it;
			if ( it != s.begin () ) {
				int b = *it, a = *-- it;
				if ( s.count( b ) > 1 ) a = b;
				if ( a + b > x ) { puts ( "Yes" ); continue; }
				a = -1;
				if ( tit != s.end () ) a = *tit;
				if ( ~ a && a - b < x ) { puts ( "Yes" ); continue; }
			}
			int r = st.pre ( x );
			if ( x > st.mn[st.ch[r][1]] ) { puts ( "Yes" ); continue; }
			puts ( "No" );
		}
	}
	return 0;
}