zoukankan      html  css  js  c++  java
  • HDU 3436 Queue-jumpers Splay

    这题用Splay写得我蛋疼菊紧,4000b的代码还有debug半天,看来我的splay姿势还不够好a = =

    首先N是很大的,所以离散化是必然的,把要Top操作的和要Query操作的编号单独划分为一个区间,然后再中间会产生其他的区间,把这些区间缩点,然后离散化就好了。

    三个操作其实不难实现,Top操作只要先把这个节点删除,然后把节点的其他值不变,key值变成一个极小值再重新插入就好,可以把极小值直接设成0,因为据说splay是稳定的,不过保险起见我还是设置了一个tpos变量维护了一下当前的极小值,还是比较方便的。

    Rank操作其实就是一个找第k大,不同的就是这里节点本身的大小有可能不是1,要稍微处理一下。

    Query操作就是找有几个节点比指定节点小,直接把这个节点splay到根,然后取左子树大小用即可。一开始我写成先找到这个节点,然后沿着父节点一路往上加的SB做法,直接TLE了两发,没有利用好splay的性质a,多伸展几下树也会平衡一点o(╯□╰)o

    至于如何快速找到person,只要维护一个数组指向节点的编号就好。

    不过感觉这题用线段树很好写a,只要在前面留Q个空位就好了。 。。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 3e5 + 10;
    int ch[maxn][2], fa[maxn], rsize[maxn], size[maxn], key[maxn], nstr[maxn], chcnt, root;
    int n, q, vnum[maxn], vcnt, qval[maxn], tpos, pos[maxn], pid[maxn];
    int node_size[maxn], node_str[maxn], node_cnt;
    char cmd[maxn][16];
    
    inline void pushup(int x) {
    	size[x] = rsize[x];
    	for (int i = 0; i < 2; i++) if (ch[x][i]) {
    		size[x] += size[ch[x][i]];
    	}
    }
    
    int getID(int v) {
    	return lower_bound(vnum, vnum + vcnt, v) - vnum;
    }
    
    void build_node() {
    	//缩点
    	for (int i = 1; i < vcnt; i++) {
    		int tmp = vnum[i] - vnum[i - 1] - 1;
    		if (tmp) {
    			node_size[++node_cnt] = tmp;
    			node_str[node_cnt] = vnum[i - 1] + 1;
    		}
    		node_size[++node_cnt] = 1;
    		node_str[node_cnt] = vnum[i];
    		pid[i] = node_cnt;
    	}
    	if (vnum[vcnt - 1] < n) {
    		node_size[++node_cnt] = n - vnum[vcnt - 1];
    		node_str[node_cnt] = vnum[vcnt - 1] + 1;
    	}
    }
    
    int newNode(int &r, int father, int v, int rz, int ns) {
    	r = ++chcnt;
    	ch[r][0] = ch[r][1] = 0;
    	rsize[r] = rz;
    	key[r] = v;
    	fa[r] = father;
    	nstr[r] = ns;
    	return r;
    }
    
    void build_tree(int l, int r, int &rt, int father) {
    	int mid = l + r >> 1;
    	rt = pos[mid] = newNode(rt, father, mid, node_size[mid], node_str[mid]);
    	if (l < mid) build_tree(l, mid - 1, ch[rt][0], rt);
    	if (r > mid) build_tree(mid + 1, r, ch[rt][1], rt);
    	pushup(rt);
    }
    
    inline void rotate(int x, int d) {
    	int y = fa[x];
    	ch[y][d ^ 1] = ch[x][d];
    	fa[ch[x][d]] = y;
    	if (fa[y]) ch[fa[y]][y == ch[fa[y]][1]] = x;
    	fa[x] = fa[y];
    	ch[x][d] = y;
    	fa[y] = x;
    	pushup(x);
    	pushup(y);
    }
    
    inline void splay(int x, int goal) {
    	while (fa[x] != goal) {
    		int y = fa[x], d = (x == ch[y][1]);
    		if (fa[y] == goal) rotate(x, d ^ 1);
    		else {
    			int z = fa[y], d1 = (y == ch[z][1]);
    			if (d == d1) {
    				rotate(y, d ^ 1); rotate(x, d ^ 1);
    			}
    			else {
    				rotate(x, d ^ 1); rotate(x, d1 ^ 1);
    			}
    		}
    	}
    	pushup(x);
    	if (goal == 0) root = x;
    }
    
    inline int findMax(int rt) {
    	while (ch[rt][1]) rt = ch[rt][1];
    	return rt;
    }
    
    inline void remove(int x) {
    	splay(x, 0);
    	int lc = ch[x][0], rc = ch[x][1];
    	if (lc) {
    		int u = findMax(lc);
    		splay(u, x);
    		fa[u] = 0;
    		if(rc) fa[rc] = u;
    		ch[u][1] = rc;
    		root = u;
    		pushup(u);
    	}
    	else if(rc) {
    		fa[rc] = 0;
    		root = rc;
    		pushup(rc);
    	}
    	else root = 0;
    }
    
    inline int insert(int v, int rz, int ns) {
    	int u = root;
    	if (root == 0) {
    		newNode(root, 0, v, rz, ns);
    		return root;
    	}
    	while (ch[u][v > key[u]]) u = ch[u][v > key[u]];
    	int r = newNode(ch[u][v > key[u]], u, v, rz, ns);
    	splay(r, 0);
    	return r;
    }
    
    inline void setTop(int x) {
    	x = pid[getID(x)];
    	remove(pos[x]);
    	pos[x] = insert(--tpos, node_size[x], node_str[x]);
    }
    
    inline int query(int x) {
    	x = pos[pid[getID(x)]];
    	splay(x, 0);
    	return size[ch[x][0]] + 1;
    }
    
    inline int findkth(int rt, int k) {
    	int lsize = size[ch[rt][0]];
    	if (lsize >= k) return findkth(ch[rt][0], k);
    	else if (lsize + rsize[rt] >= k) return nstr[rt] + k - lsize - 1;
    	else return findkth(ch[rt][1], k - lsize - rsize[rt]);
    }
    
    int main() {
    	int T; scanf("%d", &T);
    	for (int kase = 1; kase <= T; kase++) {
    		printf("Case %d:
    ", kase);
    		scanf("%d%d", &n, &q);
    		//加入把要进行Top,和Query操作的值离散化
    		vcnt = node_cnt = tpos = 0;
    		vnum[vcnt++] = 0;
    		chcnt = 0;
    		for (int i = 1; i <= q; i++) {
    			scanf("%s%d", cmd[i], &qval[i]);
    			if (cmd[i][0] == 'T' || cmd[i][0] == 'Q') {
    				vnum[vcnt++] = qval[i];
    			}
    		}
    		sort(vnum, vnum + vcnt);
    		vcnt = unique(vnum, vnum + vcnt) - vnum;
    		build_node();
    		build_tree(1, node_cnt, root, 0);
    		for (int i = 1; i <= q; i++) {
    			if (cmd[i][0] == 'T') setTop(qval[i]);
    			else if (cmd[i][0] == 'R') printf("%d
    ", findkth(root, qval[i]));
    			else printf("%d
    ", query(qval[i]));
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    VS Studio中复制窗体产生obj\Debug\SXP227\newform2.resources”在“Resources”参数中指定了多次。“Resources”参数不支持重复项 错误解决方案
    标签 frameset, frame ,noframes,iframe
    Winform GridView的允许自动生成列属性 AutoGenerateColumns
    目前自己的.Net的水平状态评估、方向
    C# 读取Excel中的时间
    asp.net中Button控件的单击回传机制
    javascript实现两个asp.net服务器控件ListBox值的互传
    关键字partial
    解决jQuery插件tipswindown与hintbox冲突
    C#数据结构三:单链表Singly Linked List
  • 原文地址:https://www.cnblogs.com/rolight/p/4278980.html
Copyright © 2011-2022 走看看