生活随笔
收集整理的這篇文章主要介紹了
[codevs 1743] 反转卡片
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
http://codevs.cn/problem/1743/
題解:
思路:采用標記的方式減少操作。rev表示該節點及子樹需要翻轉。如果在kth()查詢第k位置的卡片時走到這個節點o,就pushdown(o),把標記傳到子節點,反轉左右子節點。如果要反轉的區間為[l, r],在rever操作中,將l-1伸展到根,再將r+1節點伸展到右節點。那么對應區間可以轉化為ch[ch[o][1]][0]節點所對應的樹,給它打標記即可。
注意的問題:
1.需要虛擬節點,因為思路中rever操作很有風險。建立虛擬節點后各個點的編號要變。
2.在將某節點伸展到根的右節點時,注意k的取值,要減去根左節點的s值+1。見代碼。
3.要注意pushdown操作的位置,共有三處需要:kth中一次,splay中兩次。
3.定義了宏,挺好用的。
代碼
總時間耗費: 1782ms
總內存耗費: 5 MB
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn =
300000 +
10;
const int maxc =
100000;
int n, root, ch[maxn][
2], s[maxn], v[maxn];
bool rev[maxn];
#define lc ch[o][0]
#define rc ch[o][1]void update(
int o) { s[o] = s[lc] + s[rc] +
1;
}
void rotate(
int& o,
int d) {
int k = ch[o][d^
1]; ch[o][d^
1] = ch[k][d]; ch[k][d] = o; update(o); update(k); o = k;
}
void pushdown(
int o) { rev[o]^=
1; rev[lc]^=
1; rev[rc]^=
1; swap(lc, rc);
}
int cmp(
int o,
int k) {
if(s[lc]+
1 == k)
return -
1;
return k < s[lc]+
1 ?
0 :
1;
}
void splay(
int& o,
int k) {
if(rev[o]) pushdown(o);
int d = cmp(o, k);
if(d == -
1)
return;
if(d ==
1) k -= s[lc] +
1;
int p = ch[o][d];
if(rev[p]) pushdown(p);
int d2 = cmp(p, k);
int k2 = (d2 ==
0) ? k : k-s[ch[p][
0]]-
1;
if(d2 != -
1) {splay(ch[p][d2], k2);
if(d == d2) rotate(o, d^
1);
else rotate(ch[o][d], d);}rotate(o, d^
1);
}
void rever(
int& o,
int L,
int R) { splay(o, L); splay(rc, R-s[lc]+
1); rev[ch[rc][
0]] ^=
1;
}
void build(
int L,
int R,
int P,
int d) {
if(L == R) { s[L] =
1; ch[P][d] = L;
return; }
int M = (L+R) >>
1;
if(M-
1 >= L) build(L, M-
1, M,
0);
if(R >= M+
1) build(M+
1, R, M,
1);ch[P][d] = M; update(M);
}
int kth(
int o,
int k) {
if(rev[o]) pushdown(o);
if(s[lc]+
1 == k)
return o;
if(s[lc] >= k)
return kth(lc, k);
return kth(rc, k-s[lc]-
1);
}
int main() {
scanf(
"%d", &n);
for(
int i =
2; i <= n+
1; i++)
scanf(
"%d", &v[i]);build(
1, n+
2,
0,
0); root = (n+
3) >>
1;
int first, c =
0;
while((first = v[kth(root,
2)]) !=
1) {rever(root,
1, first);
if(++c > maxc) { c = -
1;
break; }}
printf(
"%d\n", c);
return 0;
}
總結
以上是生活随笔為你收集整理的[codevs 1743] 反转卡片的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。