Solution -「牛客多校賽 2020 Round II」Happy Triangle
阿新 • • 發佈:2020-07-14
\(\mathcal{Description}\)
link.
維護一個可重集 \(s\),支援:
- 插入 \(x\)。
- 刪除一個 \(x\),保證存在。
- 給定 \(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; }