給乙個\(1\)到\(n\)的排列
現在有\(m\)個操作,每個操作是下面的一種:
\(t\leq 10,1\leq n \leq 10^5, 1\leq m \leq 10^5 ,1\leq k\leq n\)
考場上頭鐵,硬肝了\(4h\)
結考後\(20\)分鐘調出來,\(1a...\)但想出來還是很高興的
我們會發現每次給出的\(k\)都在\([1,n]\)範圍內,那麼我們操作二中輸出的數最大也就是\(n+1\)
所以給\(pos\)位上的數加上\(10^7\)實際上相當於把這個數從排列中刪除
我們主要看第二個操作
對於\(2,3\)兩個條件,我們能夠很快想到權值線段樹維護
每次在權值線段樹中查詢\([k,n]\),在滿足條件\(1\)的情況下盡量往左走即可
那麼我們怎麼判斷是否滿足條件\(1\)呢?
我們可以發現條件\(1\)是關於位置的限制,所以我們在權值線段樹中儲存各個元素的位置並維護其最大值
那麼在查詢時按照以下的順序即可:
如果左子樹的位置最大值\(\geq r\),證明左子樹中一定有滿足條件的數,向左子樹查詢
否則如果右子樹的最大值\(\geq r\),向右子樹查詢
如果左右子樹都沒有,返回乙個極大值
在所有查詢結果中取乙個最小值即可
對於刪除操作,直接把其位置設為乙個極大值,因為只要詢問區間包含這個數,這個數必然是合法的
沒封裝,有點醜。。。
#include using namespace std;
const int n = 1e6 + 10;
const int add = 10000000;
int t, n, m, lstans;
int a[n], b[n], mx[n << 2];
inline int max(int x, int y)
inline int min(int x, int y)
void build(int root, int l, int r)
int mid = l + r >> 1;
build(root << 1, l, mid);
build(root << 1 | 1, mid + 1, r);
mx[root] = max(mx[root << 1], mx[root << 1 | 1]);
}void change(int root, int l, int r, int x)
int mid = l + r >> 1;
if (x <= mid)
change(root << 1, l, mid, x);
if (x > mid)
change(root << 1 | 1, mid + 1, r, x);
mx[root] = max(mx[root << 1], mx[root << 1 | 1]);
}int query(int root, int l, int r, int x, int y, int v)
int main() else
} }return 0;
}
2019CCPC網路選拔賽補題
hdu6703 題意就不說了,直接分析吧。對於1操作,a pos 1e7,但是我們每次詢問是 1,n 範圍內的,這個操作顯然就是把這個點給刪了。對於2操作,詢問 1,r 區間內 k且不等於a i 1 i r 的最小的數。題目做法如下 對位置建權值線段樹,每個結點表示乙個區間,每個結點維護乙個區間的位...
2019CCPC網路選拔賽簽到題題解
因為實力不濟,沒能通過網路賽拿到晉級的名額,心情沉重,故作此文記錄本次網路賽的點滴收穫。其中包含1001 1006 shuffle card 1007 windows of ccpc 1008 fishing master的題解。題目傳送門 題目分析 要找到使 ax orc a xor c axor...
2019ccpc哈爾濱補題
因為每個字串只能取乙個,剛開始是覺得全部列舉也不會超,後來想想列舉也要用深搜,所以就先記錄擁有各個字元的串,然後深搜 include using namespace std const int maxn 2e6 10 int t char s maxn vector int v 10 bool vi...