1. 程式人生 > >NOIP 2017 列隊

NOIP 2017 列隊

題目傳送門

  傳送點I

  傳送點II

題目大意

  (家喻戶曉的題目應該不需要大意)

  (我之前咋把NOIP 2017打成了NOIP 2018,好絕望)

Solution 1 Splay

  每行一顆Splay,沒有動過的地方直接一段一個點。

  最後一列單獨一顆Splay。

  暴力模擬即可。

Soluion 2 Splay II

  我們考慮倒推。對於每個詢問倒推出在第一次操作前時的位置。

  考慮每個出隊操作對答案的影響。

  假設詢問$(x, y)$,那麼最後一列橫座標大於等於$x$的位置,橫座標都會加1.

  第$x$行,縱座標大於等於$y$的位置,縱座標都會加1.

  然後再把這個位置塞進$(x, y)$。

  然後暴力模擬就好了。

Code

  1 /**
  2  * uoj
  3  * Problem#334
  4  * Accepted
  5  * Time: 4027ms
  6  * Memory: 25700k
  7  */
  8 #include <iostream>
  9 #include <cassert>
 10 #include <cstdlib>
 11 #include <cstdio>
 12 #ifndef WIN32
 13 #define
Auto "%lld" 14 #else 15 #define Auto "%I64d" 16 #endif 17 using namespace std; 18 typedef bool boolean; 19 #define ll long long 20 21 const int N = 3e5 + 5; 22 23 typedef class SplayNode { 24 public: 25 int val, tg, id; 26 SplayNode *ch[2]; 27 SplayNode *fa;
28 29 SplayNode() { } 30 31 void pushDown() { 32 for (int i = 0; i < 2; i++) 33 if (ch[i]) 34 ch[i]->val += tg, ch[i]->tg += tg; 35 tg = 0; 36 } 37 38 int which(SplayNode* p) { 39 return p == ch[1]; 40 } 41 }SplayNode; 42 43 SplayNode pool[N << 1]; 44 SplayNode* top = pool; 45 46 SplayNode* newnode(int val, int id) { 47 top->val = val, top->id = id; 48 top->ch[0] = top->ch[1] = top->fa = NULL; 49 top->tg = 0; 50 return top++; 51 } 52 53 SplayNode* stps[N]; 54 55 typedef class Splay { 56 protected: 57 void rotate(SplayNode* p) { 58 SplayNode *fa = p->fa, *ffa = fa->fa; 59 int df = fa->which(p); 60 SplayNode* ls = p->ch[df ^ 1]; 61 62 p->fa = ffa; 63 p->ch[df ^ 1] = fa; 64 fa->fa = p; 65 fa->ch[df] = ls; 66 if (ls) 67 ls->fa = fa; 68 if (ffa) 69 ffa->ch[ffa->which(fa)] = p; 70 } 71 72 void splay(SplayNode* p, SplayNode* fa) { 73 SplayNode** st = stps; 74 for (SplayNode* q = p; q; *(++st) = q, q = q->fa); 75 for ( ; st != stps; (*st)->pushDown(), st--); 76 for ( ; p->fa != fa; rotate(p)) 77 if (p->fa->fa != fa) 78 rotate((p->fa->fa->which(p->fa) == p->fa->which(fa)) ? (p->fa) : (p)); 79 if (!fa) 80 rt = p; 81 } 82 public: 83 SplayNode* rt; 84 85 void insert(SplayNode*& p, SplayNode* fa, SplayNode* np) { 86 if (!p) { 87 p = np, np->fa = fa; 88 return; 89 } 90 if (p->tg) 91 p->pushDown(); 92 insert(p->ch[np->val > p->val], p, np); 93 } 94 95 boolean less_bound(int x) { // find the maximum number less than x and splay it 96 SplayNode* ret = NULL, *p = rt, *q = NULL; 97 while (p) { 98 q = p; 99 if (p->tg) 100 p->pushDown(); 101 if (p->val < x) 102 ret = p, p = p->ch[1]; 103 else 104 p = p->ch[0]; 105 } 106 if (ret) 107 splay(ret, NULL); 108 else if (q) 109 splay(q, NULL); 110 return ret != NULL; 111 } 112 113 void remove(SplayNode* p) { 114 splay(p, NULL); 115 if (!p->ch[1]) { 116 rt = p->ch[0]; 117 if (rt) 118 rt->fa = NULL; 119 return; 120 } 121 122 SplayNode* q = p->ch[1]; 123 while (q->ch[1]) 124 q = q->ch[1]; 125 splay(q, p); 126 q->ch[0] = p->ch[0]; 127 if (p->ch[0]) 128 p->ch[0]->fa = q; 129 rt = q; 130 } 131 132 SplayNode* findMax() { 133 SplayNode* p = rt; 134 while (p && p->ch[1]) { 135 if (p->tg) 136 p->pushDown(); 137 p = p->ch[1]; 138 } 139 if (p) 140 splay(p, NULL); 141 return p; 142 } 143 144 void insert(SplayNode* p) { 145 insert(rt, NULL, p); 146 splay(p, NULL); 147 } 148 149 void getLis(SplayNode**& vs, SplayNode* p) { 150 if (!p) 151 return; 152 if (p->tg) 153 p->pushDown(); 154 *(vs++) = p; 155 getLis(vs, p->ch[0]); 156 getLis(vs, p->ch[1]); 157 } 158 }Splay; 159 160 int n, m, q; 161 Splay ls[N]; // maintain for (1, 1) - (n, m - 1) 162 Splay rs; 163 int xs[N], ys[N]; 164 ll res[N]; 165 166 inline void init() { 167 scanf("%d%d%d", &n, &m, &q); 168 for (int i = 1; i <= q; i++) 169 scanf("%d%d", xs + i, ys + i); 170 } 171 172 int uf[N]; 173 174 int find(int x) { 175 return (uf[x] == x) ? (x) : (uf[x] = find(uf[x])); 176 } 177 178 inline void solve() { 179 for (int i = 1; i <= q; i++) 180 uf[i] = i; 181 182 SplayNode *p; 183 for (int i = q; i; i--) { 184 int x = xs[i], y = ys[i]; 185 while ((p = rs.findMax()) && p->val == n) 186 uf[find(p->id)] = i, rs.remove(p); 187 if (rs.rt) { 188 if (rs.less_bound(x)) { 189 p = rs.rt->ch[1]; 190 if (p) 191 p->val++, p->tg++; 192 } else 193 rs.rt->val++, rs.rt->tg++; 194 } 195 if (y == m) { 196 rs.insert(newnode(x, i)); 197 } else { 198 Splay& sp = ls[x]; 199 if (sp.rt) { 200 if (sp.less_bound(y)) { 201 p = sp.rt->ch[1]; 202 if (p) 203 p->val++, p->tg++; 204 } else 205 sp.rt->val++, sp.rt->tg++; 206 } 207 while ((p = sp.findMax()) && p->val == m) 208 rs.insert(newnode(x, p->id)), sp.remove(p); 209 sp.insert(newnode(y, i)); 210 } 211 } 212 213 SplayNode **pp, **pq; 214 for (int i = 1; i <= n; i++) { 215 pp = stps; 216 ls[i].getLis(pp, ls[i].rt); 217 for (pq = stps; pq != pp; pq++) 218 res[(*pq)->id] = (i - 1) * 1ll * m + (*pq)->val; 219 } 220 pp = stps; 221 rs.getLis(pp, rs.rt); 222 for (pq = stps; pq != pp; pq++) 223 res[(*pq)->id] = (*pq)->val * 1ll * m; 224 for (int i = 1; i <= q; i++) 225 printf(Auto"\n", res[find(i)]); 226 } 227 228 int main() { 229 init(); 230 solve(); 231 return 0; 232 }
Splay

Solution 3 BIT

  考慮刪掉的位置我們留下,如果我們知道所有按順序被加進這一行的人,那麼我們查詢第$k$列的人相當於求第$k$大值。

  我們可以利用樹狀陣列預處理出每一行除去最後一列,每個詢問是第幾個加入這一行的數(原來的數依次看做第一個,第二個,...)。

  然後開始處理詢問。用類似的方法維護最後一列。

  這樣可以算每次詢問,最後一列被拿走的數,以及當且行被加入的數。

Code

  1 /**
  2  * uoj
  3  * Problem#334
  4  * Accepted
  5  * Time: 1673ms
  6  * Memory: 32808b
  7  */
  8 #include <iostream>
  9 #include <cstdlib>
 10 #include <cstdio>
 11 #include <vector>
 12 #ifndef WIN32
 13 #define Auto "%lld"
 14 #else
 15 #define Auto "%I64d"
 16 #endif
 17 using namespace std;
 18 typedef bool boolean;
 19 
 20 template <typename T>
 21 void pfill(T* pst, const T* ped, T val) {
 22     for ( ; pst != ped; *(pst++) = val);
 23 }
 24 
 25 const int bzmax = 20;
 26 const int N = 3e5 + 5;
 27 
 28 typedef class IndexedTree {
 29     public:
 30         int *ar;
 31         int s;
 32 
 33         IndexedTree() {    }
 34         IndexedTree(int s):s(s) {
 35             ar = new int[(s + 1)];
 36             pfill(ar, ar + s + 1, 0);
 37         }
 38 
 39         void add(int idx, int val) {
 40             for ( ; idx <= s; idx += ((-idx) & idx))
 41                 ar[idx] += val;
 42         }
 43 
 44         int kth(int k) {
 45             int rt = 0, cur = 0;
 46             for (int b = (1 << (bzmax - 1)); b; b >>= 1)
 47                 if ((rt | b) <= s && cur + ar[rt | b] < k)
 48                     rt += b, cur += ar[rt | b];
 49             return rt + 1;
 50         }
 51 }IndexedTree;
 52 
 53 #define ll long long
 54 #define pii pair<int, int>
 55 #define fi first
 56 #define sc second
 57 
 58 int n, m, q, K;
 59 int rk[N];
 60 IndexedTree it;
 61 pii qs[N];
 62 vector<ll> lst;
 63 vector<ll> vs[N];
 64 vector<pii> ms[N];
 65 
 66 inline void init() {
 67     scanf("%d%d%d", &n, &m, &q);
 68     K = max(n, m) + q;
 69     it = IndexedTree(K);
 70     for (int i = 1; i <= q; i++) {
 71         scanf("%d%d", &qs[i].fi, &qs[i].sc);
 72         if (qs[i].sc < m)
 73             ms[qs[i].fi].push_back(pii(qs[i].sc, i));
 74     }
 75 }
 76 
 77 inline void solve() {
 78     for (int i = 1; i <= K; i++)
 79         it.add(i, 1);
 80     for (int i = 1; i <= n; i++) {
 81         for (vector<pii> :: iterator it = ms[i].begin(); it != ms[i].end(); it++)
 82             ::it.add(rk[it->sc] = ::it.kth(it->fi), -1);
 83         for (vector<pii> :: iterator it = ms[i].begin(); it != ms[i].end(); it++)
 84             ::it.add(rk[it->sc], 1);
 85     }
 86 
 87     ll res;
 88     for (int i = 1, x, y, p; i <= q; i++) {
 89         x = qs[i].fi, y = qs[i].sc;
 90         it.add(p = it.kth(x), -1);
 91         res = ((p <= n) ? (p * 1ll * m) : (lst[p - n - 1]));
 92         if (y < m) {
 93             vs[x].push_back(res);
 94             res = ((rk[i] <= m - 1) ? ((x - 1) * 1ll * m + rk[i]) : vs[x][rk[i] - m]);
 95         }
 96         lst.push_back(res);
 97         printf(Auto"\n", res);
 98     }
 99 }
100 
101 int main() {
102     init();
103     solve();
104     return 0;
105 }

相關推薦

[NOIp 2017]列隊

註意 iostream esc || 女孩子 noi class cst namespace Description Sylvia 是一個熱愛學習的女孩子。 前段時間,Sylvia 參加了學校的軍訓。眾所周知,軍訓的時候需要站方陣。 Sylvia 所在的方陣中有$n

noip 2017 列隊 (45行!!!!)

這題在仔細思考(看題解)後感覺還是挺簡單的。 因為對於每一次操作只會影響當前行和最後一列,那麼我們可以用動態開點線段樹來維護每一行的前m - 1 個然後在用一個維護最後一列,那麼就可以很愉快的A了。 程式碼(45行有木有!!!!) #include<bits/

NOIP 2017 列隊(線段樹二分+動態開點)

題目描述 Sylvia 是一個熱愛學習的女孩子。 前段時間,Sylvia 參加了學校的軍訓。眾所周知,軍訓的時候需要站方陣。 Sylvia 所在的方陣中有n×mn \times mn×m名學生,方陣的行數為 nnn,列數為 mmm。 為了便於管理,教官在訓練開始時

NOIP 2017 列隊

題目傳送門   傳送點I   傳送點II 題目大意   (家喻戶曉的題目應該不需要大意)   (我之前咋把NOIP 2017打成了NOIP 2018,好絕望) Solution 1 Splay   每行一顆Splay,沒有動過的地方直接一段一個點。   最後一列單獨一顆Splay。

noip 2017 提高組

amp 子串 names ef6 space one 一個 logs sum T1 神奇的幻方 題目傳送門 就只是一道模擬題 水水水 #include<cstdio> #include<cstring> #include<algorithm

NOIP 2017 集訓散記

余數 left 下一個 ... tro 給定 跑步 割點 同余 17.10.5 Maze   題意   給定一張 $n \times m$ , 包含空地 ‘.‘ 和障礙 ‘#‘ 的格點圖.   給定起點和終點, 求從起點到終點的必須經過點有多少個.   $n, m \le

[日常] NOIP 2017滾粗記

頹廢 空間 繼續 密碼 斷開 lin 怎麽辦 還要 模擬 突然挑了這麽個滑稽的時間補了遊記... (成績日常延時再加上人太菜估計基本上就是頹廢記錄) 然而文化課太廢可能會被強制退役QAQ所以先補了再說吧 day0 一大早被老姚交代了個開十一機房門的任務... 打開

NOIP 2017 Day2 T1 奶酪

c++ names str day ica while -- 是否 ++ luogu題面 兩天中唯一的良心題,然而我在考場上蜜汁 RE 成70... 做法應該很多,樸素做法應該有 並查集 和 搜索 ; 我打的 並查集,不過好像 DFS 快的一批; 思路很簡單,就是把能連

NOIP 2017 Day1 T1 小凱的疑惑

bsp .org blank math sca ace ... nth noip luogu題面 小學奧數呵呵 在考場上40分鐘沒證出來(數學太差),運氣好看到了規律... 來一波證明: 定義 f(a,b) 表示在 gcd(a,b)==1 情況下的答案。 貝祖定理 易證

NOIP 2017 Day1 T2 時間復雜度

span nth 記錄 soft ans sof space ems noip luogu題面 大模擬...並不難(然而考場上寫掛了) 用 3 個讀入函數,解決讀入問題 雙棧齊發,一個記錄使用過的字母,另一個記錄復雜度貢獻情況 用 bre 表示當前跳出循環的層數 用

NOIP 2017 賽後反思 [補檔]

情況 noip 似的 完成 div bfs 相關 二分圖 模擬 首先寫一下比賽的情況: D1: T1: 之前做過類似的題目, 因而知道大致的結論, 迅速完成. T2: 貌似直接模擬就可以了, 涉及到字符串信息提取, 比較麻煩, 因而想放到最後做. T3: 非常簡潔的圖論題,

NOIP-2017

單單 在一起 一起 顯示 教練 快的 err 代表大會 昨天 Day0 下午來到熟悉的長沙理工,簡單到考場轉轉就各自散了。回賓館後有點淡淡的焦慮…… 晚上被教練喊去開機房人民代表大會,大家簡單討論了一下,回去後找wzy要了個對拍,然後就帶著焦慮睡下了。 Day1 進考場後

[NOIP 2017] 逛公園

i++ inf make pri edge can 最短 bits push [題目鏈接] http://uoj.ac/problem/331 [算法] 首先,我們預處理出每個點到第N個點的最短路,這等價於在反圖上求第N個點到其余點的最短路

[NOIP 2017普及組 No.2] 圖書管理員

其中 ali 一個空格 空格 size 讀者 bsp 需要 輸入格式 [NOIP 2017普及組 No.2] 圖書管理員 【題目描述】   圖書館中每本書都有一個圖書編碼,可以用於快速檢索圖書,這個圖書編碼是一個正整數。   每位借書的讀者手中有一個需求碼,這個需求碼也是一

[NOIP 2017普及組 No.3] 棋盤

要花 code strong 開始 分開 格子 ron 一個空格 連續 [NOIP 2017普及組 No.3] 棋盤 【題目描述】 有一個m × m的棋盤,棋盤上每一個格子可能是紅色、黃色或沒有任何顏色的。你現在要從棋盤的最左上角走到棋盤的最右下角。 任何一個時刻,

[NOIp 2017] Complexity

string corona pac 我不 查詢 () 一次 [] 初始 洛谷 3952 輸入一整行字符串時,如果中間有空格,則不能用 scanf("%s",...) 來輸入! scanf() 會在空格處停下! 在NOIp2018 前夕終於做出了NOIp2017的題 Cand

NOIP 2017 逛公園

題目連結 https://www.luogu.org/problemnew/show/P3953   覺得是dp,想了一個n*最短路長度的dp 發現數組開不下…… 而且我也不知道怎麼在圖上做dp 不是DAG,不能拓撲   然後就寫了個K=0的情況,寫了個最短路計數,水了30

NOIP 2017 Day1 T2 時間複雜度 complexity - 模擬題 題解

作者@豪噠噠噠HaoDaDaDa 轉載自簡書@豪噠噠噠HaoDaDaDa-簡書-NOIP 2017 Day1 T2 時間複雜度 (有一個月沒有寫簡書了…) (這次終於開始拿Markdown寫了,富文字可以走開了) 說說為什麼我要寫這道題… 因為…dalao們寫的都是兩百多行的程式碼看不懂

NOIP 2017 寶藏 - 動態規劃

題目傳送門   傳送門 題目大意   (家喻戶曉的題目不需要題目大意)   設$f_{d, s}$表示當前樹的深度為$d$,與第一個打通的點連通的點集為$s$。   每次轉移的時候不考慮實際的深度,深度都當做$d$,尋找連線兩個點集最小邊集,如果能連線更淺的點,那麼會在之前轉移,

最短路+拓撲排序+dp NOIP 2017 逛公園

讓我們一起來%forever_shi神犇 題意: 給你一個 n n n個點