luoguP3939 數顏色
阿新 • • 發佈:2020-08-03
題解
懶得寫題,又不想頹,所以開始水題解。
大意就是維護一個序列,要求支援兩種操作:一是在給出的區間內查詢某個值的出現次數,二是交換相鄰某兩個的元素。
一看到區間操作就想到了線段樹...於是開始打主席樹,打到一半發現不會打...又改成普通線段樹,打完後發現比暴力還慢上好幾倍...主要是顏色可能有很多種,而且相當分散,線段樹的區間效果體現不出來...
然後這道題還很是毒瘤地卡了主席樹,ST表...甚至它連分塊都卡了...(出題人這樣惡意滿滿不會折陽壽嗎)
於是,面對3e5的資料,資料結構已經GG了,還有什麼能夠拯救我們呢?沒錯,那就是我們的STL!(STL大法好)(然鵝上一題的lower_bound就被卡飛了)
因為顏色的種類很多,分佈又很稀疏,用陣列來儲存是不可能的,但是,我們有偉大的\(vector\)
直接反手開一個vector,\(vector[i]\)表示\(i\)這個顏色依次出現的下標,就算你資料再怎麼毒瘤,只要我動態開記憶體不就好了嗎,反正就算是由於\(vector\)的特性它最多也就6e5的記憶體,完全夠了。另外由於我們在讀入時直接記錄,所以它一定是滿足單調上升的,所以在查詢時可以二分優化一下。
具體的實現參見程式碼吧。
#include <bits/stdc++.h> using namespace std; #define ll long long char buf[1 << 20], *p1, *p2; char getc() { if(p1 == p2) { p1 = buf; p2 = buf + fread(buf, 1, 1 << 20, stdin); if(p1 == p2) return EOF; } return *p1++; } inline ll read() { ll s = 0, w = 1; char c = getc(); while(c < '0' || c >'9') {if(c == '-')w = -1; c = getc();} while(c >= '0' && c <= '9') s = s * 10 + c - '0', c = getc(); return s * w; } const int maxn = 3e5 + 100; int n, m; int a[maxn]; vector<int> col[maxn]; int main() { n = read(), m = read(); for(register int i = 1; i <= n; i++) { a[i] = read(); col[a[i]].push_back(i); } int op, x, y, z; int it1, it2; for(register int i = 1; i <= m; i++) { op = read(); if(op == 1) { x = read(), y = read(), z = read(); it1 = lower_bound(col[z].begin(), col[z].end(), x) - col[z].begin(); it2 = upper_bound(col[z].begin(), col[z].end(), y) - 1 - col[z].begin(); printf("%d\n", it2 - it1 + 1); } else { x = read(); if(a[x] == a[x + 1]) continue; it1 = lower_bound(col[a[x]].begin(), col[a[x]].end(), x) - col[a[x]].begin(); col[a[x]][it1]++; it2 = lower_bound(col[a[x + 1]].begin(), col[a[x + 1]].end(), x + 1) - col[a[x + 1]].begin(); col[a[x + 1]][it2]--; swap(a[x], a[x + 1]); } } }