zoukankan      html  css  js  c++  java
  • NOIP 模拟 序列操作

    题意:

    一开始有n个非负整数h[i],接下来会进行m次操作,第i次会给出一个数c[i],要求选出c[i]个大于0的数并将它们-1,问最多可以进行多少次?

    分析:

    首先一个显然的贪心就是每次都将最大的c[i]个数-1,于是就可以用无旋式treap来维护,基本操作中split_k和split_v都使用普通的merge,但在提取区间并打完标记后,因为整个序列的单调性发生改变,需要使用启发式合并(只在修改过后使用)。

    code

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<string>
    #include<algorithm>
    #include<cmath>
    #include<vector>
    #include<ctime>
    #include<queue>
    using namespace std;
    template<typename T>
    inline void read(T &x) {
        T i = 0, f = 1;
        char ch = getchar();
        for(; (ch < '0' || ch > '9') && ch != '-'; ch = getchar());
        if(ch == '-') f = -1, ch = getchar();
        for(; ch >= '0' && ch <= '9'; ch = getchar()) i = (i << 3) + (i << 1) + (ch - '0');
        x = i * f;
    }
    template<typename T>
    inline void wr(T x) {
        if(x < 0) putchar('-'), x = -x;
        if(x > 9) wr(x / 10);
        putchar(x % 10 + '0');
    }
    const int N = 1e6 + 50, OO = 0x3f3f3f3f;
    int n, m, h[N], c[N];
    inline int Rand(){
    	static int RAND_VAL = 1388593021;
    	return RAND_VAL += RAND_VAL << 2 | 1;
    }
    #define SZ(x) (x?x->sze:0)
    #define V(x) (x?x->val:OO)
    struct node{
    	node *lc, *rc;
    	int sze, pri, val, tag;
    	node():lc(NULL), rc(NULL){}
    	inline void add(int v){
    		val += v, tag += v;
    	}
    	inline void pushDown(){
    		if(tag != 0){
    			if(lc) lc->add(tag);
    			if(rc) rc->add(tag);
    			tag = 0;
    		}
    	}
    	inline node* upt(){
    		sze = SZ(lc) + SZ(rc) + 1;
    		return this;
    	}
    	inline void print(){
    		pushDown();
    		if(lc) lc->print();
    		cout<< val<<" ";
    		if(rc) rc->print();
    	}
    }pool[N], *tail = pool, *rt = NULL;
    inline node* newNode(int v){
    	node *x = tail++;
    	x->val = v;
    	x->lc = x->rc = NULL;
    	x->pri = Rand();
    	x->tag = 0;
    	x->sze = 1;
    	return x;
    }
    inline node* Merge_o(node *x, node *y){
    	if(!x) return y;
    	if(!y) return x;
    	node *L, *R;
    	if(x->pri < y->pri){
    		x->pushDown();
    		x->rc = Merge_o(x->rc, y);
    		return x->upt();
    	}
    	else {
    		y->pushDown();
    		y->lc = Merge_o(x, y->lc);
    		return y->upt();
    	}
    }
    inline void Split_v(node *x, int v, node *&L, node *&R);
    inline node* Merge(node *x, node *y){
    	if(!x) return y;
    	if(!y) return x;
    	x->pushDown(), y->pushDown();
    	if(x->pri > y->pri) swap(x, y);
    	node *L, *R;
    	Split_v(y, x->val, L, R);
    	x->lc = Merge(x->lc, L);
    	x->rc = Merge(x->rc, R);
    	x->upt();
    	return x;
    }
    inline void Split_k(node *x, int k, node *&L, node *&R){
    	if(x == NULL){L = NULL, R = NULL; return;}
    	x->pushDown();
    	if(SZ(x->lc) < k){
    		Split_k(x->rc, k - SZ(x->lc) - 1, L, R);
    		x->rc = NULL; x->upt();
    		L = Merge_o(x, L);
    	}
    	else{
    		Split_k(x->lc, k, L, R);
    		x->lc = NULL; x->upt();
    		R = Merge_o(R, x);
    	}
    }
    inline void Split_v(node *x, int v, node *&L, node *&R){
    	if(x == NULL){L = NULL, R = NULL; return;}
    	x->pushDown();
    	if(V(x) <= v){
    		Split_v(x->rc, v, L, R);
    		x->rc = NULL; x->upt();
    		L = Merge_o(x, L);
    	}
    	else{
    		Split_v(x->lc, v, L, R);
    		x->lc = NULL, x->upt();
    		R = Merge_o(R, x);
    	}
    }
    inline node* build(){
    	static node* stk[N];
    	node* pre;
    	int top = 0;
    	for(register int i = 1; i <= n; i++){
    		node *x = newNode(h[i]);
    		pre = NULL;
    		while(top && stk[top]->pri > x->pri)
    			pre = stk[top]->upt(),  stk[top--] = NULL;
    		if(stk[top]) stk[top]->rc = x;
    		x->lc = pre; stk[++top] = x;
    	}
    	while(top) stk[top--]->upt();
    	return stk[1];
    }
    int main(){
    	freopen("h.in", "r", stdin);
    	read(n), read(m);
    	for(register int i = 1; i <= n; i++) read(h[i]);
    	for(register int i = 1; i <= m; i++) read(c[i]);
    	sort(h + 1, h + n + 1);
    	rt = build();
    	for(register int i = 1; i <= m; i++){
    		if(!c[i]) continue;
    		if(c[i] > n){
    			wr(i - 1);
    			return 0;
    		}
    		node *L, *R, *p, *q;
    		Split_v(rt, 0, L, R);
    		if(SZ(R) >= c[i]){
    			Split_k(R, SZ(R) - c[i], p, q);
    			if(q) q->add(-1);
    			R = Merge(p, q);
    		}
    		else{
    			wr(i - 1);
    			return 0;
    		}
    		rt = Merge(L, R);
    	}
    	wr(m);
    	return 0;
    }
    
    
  • 相关阅读:
    C语言字符串之无重复字符的最长子串
    C语言递归之求根到叶节点数字之和
    C语言递归之二叉树的最大深度
    C语言递归之翻转二叉树
    C语言递归之对称二叉树
    C语言链表之两数相加
    如何把笔记本电脑的有线网分享给手机上
    安利spacemacs ^^
    lambda创世纪
    jinterface包详解
  • 原文地址:https://www.cnblogs.com/CzYoL/p/7794407.html
Copyright © 2011-2022 走看看