zoukankan      html  css  js  c++  java
  • A simple simulation problem [HDU4973]

    【题目描述】
    翻译:初始时按顺序排着一排细胞 第(i)个的种类是(i)

    两种操作 第一种是把当前的第(lsim r)个细胞原地翻倍
    第二种是查询当前第(lsim r)个细胞中 数量最多的同种细胞有多少个

    (nle 5*10^4),任何时候细胞总数不超过(5*10^{12})

    举个例子 原来的细胞序列是({1,2,3,3,4,5})([2,5])翻倍 得到({1,2,2,3,3,3,3,4,4,5})

    题解

    大概1min就想到正解了QAQ(可能是因为这个是线段树专题 所以明示要用线段树) 但是调了1h才AC

    非常显然 不管怎么超级加倍这个细胞序列肯定都是一个不降的序列 同种细胞全部都在连续的一段里面

    那我们用线段树维护一下每种细胞有多少个 然后不管是修改还是查询 都先在线段树上二分找到第(l)个及第(r)个位置是什么细胞 不妨设第(l)个是(x),第(r)个是(y)

    然后我们还要查出来([l,r])中有多少个(x)多少个(y) 这个其实在线段树二分的时候就可以顺便查到了 我实现的比较毒瘤 用了个pair。。。

    那么种类为(x+1sim y-1)的那些细胞肯定全部都被包含在([l,r])之间了 对于修改操作直接区间给乘个(2)就好 查询也就是查一下区间最大值

    然后把(x,y)单独处理一下 修改操作的话就现在([l,r])区间里有多少个(x)(我们刚才已经求过了)就给(x)加上多少 查询就比一下大小。。。

    完事啦 时间复杂度(O(n log n))

    代码

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<ll, ll> pii;
    
    inline ll read() {
    	ll x = 0, f = 1; char ch = getchar();
    	for (; ch > '9' || ch < '0'; ch = getchar()) if (ch == '-') f = -1;
    	for (; ch <= '9' && ch >= '0'; ch = getchar()) x = (x << 3) + (x << 1) + (ch ^ '0');
    	return x * f; 
    }
    
    ll ttt, n, m;
    char s[5];
    
    struct segtree{
    	ll l, r, mx, sum, tag;
    } tr[200005];
    
    void build(ll ind, ll l, ll r) {
    	tr[ind].l = l; tr[ind].r = r; tr[ind].tag = 1;
    	if (l == r) {
    		tr[ind].mx = tr[ind].sum = 1;
    		return;
    	}
    	ll mid = (l + r) >> 1;
    	build(ind<<1, l, mid); build(ind<<1|1, mid+1, r);
    	tr[ind].mx = max(tr[ind<<1].mx, tr[ind<<1|1].mx);
    	tr[ind].sum = tr[ind<<1].sum + tr[ind<<1|1].sum;
    }
    
    inline void pushdown(ll ind) {
    	ll v = tr[ind].tag; tr[ind].tag = 1;
    	tr[ind<<1].tag *= v; tr[ind<<1].mx *= v; tr[ind<<1].sum *= v;
    	tr[ind<<1|1].tag *= v; tr[ind<<1|1].mx *= v; tr[ind<<1|1].sum *= v;
    }
    
    void update(ll ind, ll pos, ll v) {
    	ll l = tr[ind].l, r = tr[ind].r;
    	if (l == r) {
    		tr[ind].mx += v;
    		tr[ind].sum += v;
    		return;
    	}
    	pushdown(ind);
    	ll mid = (l + r) >> 1;
    	if (pos <= mid) update(ind<<1, pos, v);
    	else update(ind<<1|1, pos, v);
    	tr[ind].mx = max(tr[ind<<1].mx, tr[ind<<1|1].mx);
    	tr[ind].sum = tr[ind<<1].sum + tr[ind<<1|1].sum;
    }
    
    void update2(ll ind, ll x, ll y, ll v) {
    	if (x > y) return;
    	ll l = tr[ind].l, r = tr[ind].r;
    	if (x <= l && r <= y) {
    		tr[ind].tag *= v;
    		tr[ind].mx *= v;
    		tr[ind].sum *= v;
    		return;
    	}
    	pushdown(ind);
    	ll mid = (l + r) >> 1;
    	if (x <= mid) update2(ind<<1, x, y, v);
    	if (mid < y) update2(ind<<1|1, x, y, v);
    	tr[ind].mx = max(tr[ind<<1].mx, tr[ind<<1|1].mx);
    	tr[ind].sum = tr[ind<<1].sum + tr[ind<<1|1].sum;
    }
    
    pii find(ll ind, ll k, ll tp) {
    	ll l = tr[ind].l, r = tr[ind].r;
    	if (l == r) {
    		if (!tp) return make_pair(l, tr[ind].sum - k + 1);
    		else return make_pair(l, k);
    	}
    	pushdown(ind);
    	if (k <= tr[ind<<1].sum) return find(ind<<1, k, tp);
    	else return find(ind<<1|1, k - tr[ind<<1].sum, tp);
    }
    
    ll query(ll ind, ll x, ll y) {
    	if (x > y) return 0ll;
    	ll l = tr[ind].l, r = tr[ind].r;
    	if (x <= l && r <= y) {
    		return tr[ind].mx;
    	}
    	pushdown(ind);
    	ll mid = (l + r) >> 1, ret = 0;
    	if (x <= mid) ret = max(ret, query(ind<<1, x, y));
    	if (mid < y) ret = max(ret, query(ind<<1|1, x, y));
    	return ret;
    }
    
    int main() {
    	ttt = read();
    	for (ll kkk = 1; kkk <= ttt; kkk++) {
    		printf("Case #%lld:
    ", kkk);
    		n = read(); m = read();
    		build(1, 1, n);
    		for (ll i = 1, x, y; i <= m; i++) {
    			scanf("%s", s); x = read(); y = read();
    			if (s[0] == 'Q') {
    				ll ans = 0;
    				pii l = find(1, x, 0), r = find(1, y, 1); 
    				if (l.first == r.first) {
    					ans = y - x + 1;
    				} else {
    					ans = max(l.second, r.second);
    					ans = max(ans, query(1, l.first+1, r.first-1));
    				}
    				printf("%lld
    ", ans);
    			} else {
    				pii l = find(1, x, 0), r = find(1, y, 1);
    				if (l.first == r.first) {
    					update(1, l.first, y - x + 1);
    				} else {
    					update(1, l.first, l.second); update(1, r.first, r.second);
    					update2(1, l.first + 1, r.first - 1, 2);
    				}
    			}
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    Unicode与JavaScript详解 [很好的文章转]
    4种方法生成二维码 (js 控制canvas 画出 二维码)
    JQuery-Dialog(弹出窗口,遮蔽窗口)
    JQuery实现可编辑的表格
    7个提高效率的JavaScript调试工具
    jQuery中的编程范式
    10款CSS3按钮
    jQuery(function(){})与(function(){})(jQuery)的区别
    JQuery之ContextMenu(右键菜单)
    糟糕的css用法 1
  • 原文地址:https://www.cnblogs.com/ak-dream/p/AK_DREAM67.html
Copyright © 2011-2022 走看看