zoukankan      html  css  js  c++  java
  • BZOJ3506 BZOJ1552 排序机械臂 Splay区间翻转(数组版自底向上的写法)

    首先做了这题才知道自己根本不会Splay, 虽然写过几个题目, 但是区间翻转标记下放没有仔细想过, 想想以前的区间翻转题目, 恰好没有考虑到我忽略的部分, 那就是标记下放的问题, 例如BZOJ3223每次操作会先找到区间两端, 注意到在找的过程中就会下放标记, 所以Splay(){}里面不需要下放标记, 但实际上如果直接知道了要把某个节点旋上来, 比如本题, 就要在Splay前先把当前节点到目标节点(或者到根)这条链上的标记都下放, 而且考虑到父亲的标记会影响儿子, 要从上到下放标记

    本题相关:

    直接用权值做编号

    1.翻转L-->R这段只需将L-1旋到根, (R+1)旋到根的右儿子, 则L-->R的数全部在(R+1)的左儿子上了, 为了防止边界溢出(L为第一个数, 则(L-1)不存在, 或者R为末尾的数), 左右各加一个虚拟节点, 显然在题目给出的序列中每个数加上1是不影响答案的, 所以虚拟节点编号为1, n+2;

    2.调出来交上去发现TLE了, 突然发现序列的数可以重复, 太恶心了, 那么离散化, 将中间的n个数从小到大编号为2-->n+1, 而且根据题意, 相同的数位置靠前的编号也靠前, 只要记录下位置排序时考虑到就行了, 最后按照位置再排一次序, 就得到了编号后的原序列, 编号各不相同;

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    const int maxn = 100007; 
    inline int read() {
        int x = 0, f = 1; char ch = getchar();
        while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
        while(ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
        return x * f;
    }
    
    //SSSSSSSppppppplllllllaaaaaaayyyyyyy
    int n, root, sz, size[maxn], fa[maxn], c[maxn][2], val[maxn], rev[maxn];
    int top, s[maxn];
    struct seq {
    	int v, id, pos;
    } a[maxn];
    bool cmp1(seq a, seq b) {
    	return a.v < b.v || (a.v == b.v && a.pos < b.pos);
    }
    bool cmp2(seq a, seq b) {
    	return a.pos < b.pos;
    }
    void update(int x) {
    	size[x] = size[c[x][0]] + size[c[x][1]] + 1;
    }
    void push_down(int x) {
    	if(rev[x]) {
    		int l = c[x][0], r = c[x][1];
    		swap(c[x][0], c[x][1]);
    		rev[l] ^= 1; rev[r] ^= 1;
    		rev[x] = 0;
    	}
    }
    void rotate(int x, int &k) {
    	int y = fa[x], z = fa[y], l, r;
    	l = (c[y][0] == x) ? 0 : 1; r = l ^ 1; 
    	if(y == k) k = x;
    	else {
    		if(c[z][0] == y) c[z][0] = x;
    		else c[z][1] = x;
    	}
    	fa[x] = z; fa[y] = x; fa[c[x][r]] = y;
    	c[y][l] = c[x][r]; c[x][r] = y;
    	update(y); update(x);
    } 
    void splay(int x, int &k) {
    	top = 0;
    	for(int i = x; fa[i]; i = fa[i]) s[++top] = i;
    	for(int i = top; i >= 1; i--) push_down(s[i]);
    	//标记要从上到下传, 不然可能下面标记清空后又被上面传下来, 这样就不能处理完这条链上的标记 
    	/*原来做BZOJ3223的时候由于每次操作需要先找到要操作的节点, 找的过程中就down了所有标记, 所以不用这一步, 
    	结果做这题的时候到处考虑标记, 调了半天发现标记push_down顺序错了, 看来我根本不会Splay */ 
    	while(x != k) {
    		int y = fa[x], z = fa[y];
    		if(y != k) {
    			if((c[z][0] == y) ^ (c[y][0] == x)) rotate(x, k);
    			else rotate(y, k);
    		} rotate(x, k);
    	}
    } 
    
    int find(int x, int rk) {
    	if(!x) return 0;
    	push_down(x);
    	if(rk == size[c[x][0]] + 1) return x;
    	else if(rk <= size[c[x][0]]) return find(c[x][0], rk);
    	else return find(c[x][1], rk - size[c[x][0]] - 1); 
    }
    
    void build(int l, int r, int f) {
    	if(l > r) return;
    	int now = a[l].id, last = a[f].id;
    	if(l == r) {
    		fa[now] = last; size[now] = 1;
    		if(l < f) c[last][0] = now;
    		else c[last][1] = now;
    	} else {
    		int mid = (l + r) >> 1;
    		now = a[mid].id;
    		build(l, mid - 1, mid);
    		build(mid + 1, r, mid);
    		fa[now] = last; update(now);
    		if(mid < f) c[last][0] = now;
    		else c[last][1] = now;
    	}
    }
    void solve(int k) {
    	splay(k, root);
    	printf("%d", size[c[root][0]]);
    	if(k != n + 1) printf(" ");
    	int x = find(root, k - 1), y = find(root, size[c[root][0]] + 2);
    	splay(x, root); splay(y, c[x][1]);
    	rev[c[y][0]] ^= 1;
    }
    //
    
    int main() {
    	n = read();
    	//这个题最恶心的地方, 有重复编号, 需要离散化 
    	for(int i = 1; i <= n; i++) a[i + 1].v = read(), a[i + 1].v++, a[i + 1].pos = i;
    	//左右各添加一个虚拟节点, 相当于原题上所有编号都增加了1 
    	sort(a + 2, a + n + 2, cmp1);
    	for(int i = 2; i <= n + 1; i++) a[i].id = i;
    	a[1].id = 1; a[n + 2].id = n + 2;
    	sort(a + 2, a + n + 2, cmp2);
    	build(1, n + 2, 0); root = a[(n + 3) >> 1].id;
    	for(int i = 1; i <= n; i++) solve(i + 1);
    	return 0;
    }
    

      

  • 相关阅读:
    搭建Springboot+mybatis+redis+druid
    搭建Springboot+mybatis+redis+druid
    Uber是一部无所不在的数字出行物联网
    Uber是一部无所不在的数字出行物联网
    Uber是一部无所不在的数字出行物联网
    Uber是一部无所不在的数字出行物联网
    详解光伏扶贫模式 参与部门和各扮演的角色
    详解光伏扶贫模式 参与部门和各扮演的角色
    深入解析:从源码窥探MySQL优化器
    如何解决NetBeans9出现java.lang.StackOverflowError问题
  • 原文地址:https://www.cnblogs.com/usingnamespace/p/5165321.html
Copyright © 2011-2022 走看看