您的位置:首页 > 其它

BZOJ 3223: Tyvj 1729 文艺平衡树

2016-05-11 18:59 211 查看
BZOJ 3223

十分裸的一个splay模板题,标记法处理翻转。

#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;

struct Node {
Node *ch[2];
int s;
int flip;
int v;
int cmp(int k) const {
int d = k - ch[0]->s;
if(d == 1) return -1;
return d <= 0 ? 0 : 1;
}
void maintain() {
s = ch[0]->s + ch[1]->s + 1;
}
void pushdown() {
if(flip) {
flip = 0;
swap(ch[0], ch[1]);
ch[0]->flip = !ch[0]->flip;
ch[1]->flip = !ch[1]->flip;
}
}
};

Node *null = new Node();

void rotate(Node* &o, int d) {
Node* k = o->ch[d^1]; o->ch[d^1] = k->ch[d]; k->ch[d] = o;
o->maintain(); k->maintain(); o = k;
}

void splay(Node* &o, int k) {
o->pushdown();
int d = o->cmp(k);
if(d == 1) k -= o->ch[0]->s + 1;
if(d != -1) {
Node* p = o->ch[d];
p->pushdown();
int d2 = p->cmp(k);
int k2 = (d2 == 0 ? k : k - p->ch[0]->s - 1);
if(d2 != -1) {
splay(p->ch[d2], k2);
if(d == d2) rotate(o, d^1); else rotate(o->ch[d], d);
}
rotate(o, d^1);
}
}

// 合并left和right。假定left的所有元素比right小。注意right可以是null,但left不可以
Node* merge(Node* left, Node* right) {
splay(left, left->s);
left->ch[1] = right;
left->maintain();
return left;
}

// 把o的前k小结点放在left里,其他的放在right里。1<=k<=o->s。当k=o->s时,right=null
void split(Node* o, int k, Node* &left, Node* &right) {
splay(o, k);
left = o;
right = o->ch[1];
o->ch[1] = null;
left->maintain();
}

const int maxn = 100000 + 10;
struct SplaySequence {
int n;
Node seq[maxn];
Node *root;

Node* build(int sz) {
if(!sz) return null;
Node* L = build(sz/2);
Node* o = &seq[++n];
o->v = n; // 节点编号
o->ch[0] = L;
o->ch[1] = build(sz - sz/2 - 1);
o->flip = o->s = 0;
o->maintain();
return o;
}

void init(int sz) {
n = 0;
null->s = 0;
root = build(sz);
}
};

vector<int> ans;
void print(Node* o) {
if(o != null) {
o->pushdown();
print(o->ch[0]);
ans.push_back(o->v);
print(o->ch[1]);
}
}

void debug(Node* o) {
if(o != null) {
o->pushdown();
debug(o->ch[0]);
printf("%d ", o->v-1);
debug(o->ch[1]);
}
}

SplaySequence ss;
int main()
{
freopen("p3223.in", "r", stdin);
int n, m;
scanf("%d%d", &n, &m);
ss.init(n+1); // 最前面有一个虚拟结点

while (m--) {
int a, b;
scanf("%d%d", &a, &b);
Node *left, *mid, *right, *o;
split(ss.root, a, left, o); // 如果没有虚拟结点,a将改成a-1,违反split的限制
split(o, b-a+1, mid, right);
mid->flip ^= 1;
ss.root = merge(merge(left, mid), right);
}

print(ss.root);
for(int i = 1; i < ans.size(); i++)
printf("%d ", ans[i]-1); // 节点编号减1才是本题的元素值

retur
4000
n 0;
}


二周目

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<vector>
using namespace std;

struct Node{
Node* ch[2];
int v, s, flag;
int cmp(int k) const{
int d = k - ch[0]->s;
if(d == 1) return -1;
return d <= 0 ? 0 : 1;
}
void pushdown(){
if(flag){
flag = 0;
swap(ch[0], ch[1]);
ch[0]->flag ^= 1;
ch[1]->flag ^= 1;
}
}
void maintain(){
s = ch[0]->s + ch[1]->s + 1;
}
};
Node* null = new Node();

void rotate(Node* &o, int d){
Node* k = o->ch[d^1]; o->ch[d^1] = k->ch[d]; k->ch[d] = o;
o->maintain(); k->maintain(); o = k;
}

void splay(Node* &o, int k){
o->pushdown();
int d = o->cmp(k);
if(d == 1) k -= o->ch[0]->s + 1;
if(d != -1){
Node* p = o->ch[d];
p->pushdown();
int d2 = p->cmp(k);
int k2 = (d2 == 0 ? k : k - p->ch[0]->s - 1);
if(d2 != -1){
splay(p->ch[d2], k2);
if(d == d2) rotate(o, d^1); else rotate(o->ch[d], d);
}
rotate(o, d^1);
}
}

Node* merge(Node* left, Node* right){
splay(left, left->s);
left->ch[1] = right;
left->maintain();
return left;
}

void split(Node* o, int k, Node* &left, Node* &right){
splay(o, k);
left = o;
right = o->ch[1];
o->ch[1] = null;
left->maintain();
}

struct Splay{
Node* root;
int n;

Node* build(int sz){
if(!sz) return null;
Node* o = new Node();
o->ch[0] = build(sz/2);
o->v = ++n;
o->flag = o->s = 0;
o->ch[1] = build(sz - sz/2 - 1);
o->maintain();
return o;
}

void init(int sz){
n = 0;
null->s = 0;
root = build(sz);
}

vector<int> ans;
void outit(Node* o){
if(o != null){
o->pushdown();
outit(o->ch[0]);
ans.push_back(o->v);
outit(o->ch[1]);
}
}
} tr;

int n, m;
int main(){
freopen("p3223.in", "r", stdin);
scanf("%d%d", &n, &m);
tr.init(n+1);
int l, r;
while(m--){
scanf("%d%d", &l, &r);
Node *left, *right, *mid, *o;
split(tr.root, l, left, o);
split(o, r-l+1, mid, right);
mid->flag ^= 1;
tr.root = merge( merge(left, mid), right );
}
tr.outit(tr.root);
for(int i = 1; i < tr.ans.size(); i++)
printf("%d ", tr.ans[i] - 1);
cout<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: