• CF1172F Nauuo and Bug


    题目链接

    只想到一种离线后需要支持区间加,大于 (p) 的值减 (p),单点查操作的做法,但是并不会。

    考虑到一个区间减 (p) 的次数是有限的,即 (cnt in [0,len])。如果我们能够对每个 (cnt) 求出传入哪个区间的数能够恰好减 (cnt)(p) 的话,就可以快速求出 (x) 出进去后传出的是什么了。

    考虑用线段树维护。设 (c_x) 表示经过当前节点的区间要想减 (x)(p) 的最小的传入值,由此可以推出减 (x) 次对应的值的区间((c_x...c_{x+1}-1))。

    考虑如何合并两个节点。我们有一个 (O(len_l imes len_r)) 的做法:(是取最小值)

    [c_{now,x+y} gets max(c_{l,x},c_{r,y}+xp-sum_{l}) ]

    (需要同时符合大于等于 (c_x) 和大于等于 (c_y+xp-sum_l) 的条件)

    显然这个是可以优化的。假设我们外层循环 (x),内层循环 (y)。发现 (y) 大到某种程度的时候,左区间的减 (x) 次的范围中最大的那个数都不能让右区间的减的次数达到 (y),那么当 (y) 更大的时候显然也是不可行的(不合法,可忽略),于是可以直接退出。

    还可以发现,当 (x) 增加一, (y) 减少一的时候一定不会更优。考虑这种情况发生后,(c_x) 增大至少 (p)(c_y+xp-sum_l) 减少至少 (0)。如果原来 (c_x) 较大,那么现在显然不会更优。如果原来右边较大,那么原来肯定是 (c_x ... c_{x+1}-1) 中有一个数传进去后落到了 (c_y)(否则不合法可忽略,之前就不会到那里),如果现在 (c_x) 较大,不优(同上);如果现在 (c_y+xp-sum_l) 较大,那么一定是 (c_x...c_{x+1}-1) 中有一个数传进去后落到了 (c_y),而现在 (x) 增大了一,(y) 减小了一,显然是不可能的。

    于是可以用指针扫描 (O(len)) 合并。

    关键代码:

    void build(int L, int R, int &cur) {
    	cur = ++ttot; sm[cur] = sum[R] - sum[L - 1];
    	if (L == R) {
    		vec[cur].push_back(-inf);
    		vec[cur].push_back(p - sm[cur]);
    		vec[cur].push_back(inf);
    		return ;
    	}
    	int mid = (L + R) >> 1; build(L, mid, ls[cur]); build(mid + 1, R, rs[cur]);
    	for (int i = 0; i <= R - L + 2; ++i)	vec[cur].push_back(inf);
    	vec[cur][0] = -inf;
    	int ptr = 0, Ls = ls[cur], Rs = rs[cur];
    	for (int i = 0; i <= mid - L + 1; ++i) {
    		while (1) {
    			ll tmp = vec[Ls][i + 1] - 1 + sm[Ls] - 1ll * i * p;
    			if (tmp < vec[Rs][ptr]) {
    				if (ptr) --ptr; break;
    			}
    			MIN(vec[cur][i + ptr], max(vec[Ls][i], vec[Rs][ptr] + 1ll * i * p - sm[Ls]));
    			if (ptr + 1 > R - mid)	break;
    			++ptr;
    		}
    	}
    }
    
    ll query(int L, int R, int l, int r, ll x, int cur) {
    	if (l <= L && R <= r) {
    		int cnt = upper_bound(vec[cur].begin(), vec[cur].end(), x) - vec[cur].begin() - 1;
    		return x - 1ll * cnt * p + sm[cur];
    	}
    	int mid = (L + R) >> 1;
    	if (l <= mid && r > mid) {
    		x = query(L, mid, l, r, x, ls[cur]);
    		return query(mid + 1, R, l, r, x, rs[cur]);
    	}
    	if (l <= mid)	return query(L, mid, l, r, x, ls[cur]);
    	return query(mid + 1, R, l ,r, x, rs[cur]);
    }
    
  • 相关阅读:
    flask 跨域问题
    pip 命令参数说明
    关于ASP.NET动态加载控件的几点实用总结
    记录代码运行耗时的写法
    DevExpress AspxGridView数据绑定
    发现一个Membership的bug
    asp.net页面中文件下载的2种方式
    【部分转】innerText 跟 innerHTML区别
    gridview 的添加删除等技巧 全部按名称取值
    关于Linq to DataTable not in的写法
  • 原文地址:https://www.cnblogs.com/JiaZP/p/13680779.html
Copyright © 2020-2023  润新知