• 【bzoj3110】[Zjoi2013]K大数查询 整体二分+树状数组区间修改


    题目描述

    有N个位置,M个操作。操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c。如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少。

    输入

    第一行N,M
    接下来M行,每行形如1 a b c或2 a b c

    输出

    输出每个询问的结果

    样例输入

    2 5
    1 1 2 1
    1 1 2 2
    2 1 1 2
    2 1 1 1
    2 1 2 3

    样例输出

    1
    2
    1


    题解

    整体二分+树状数组区间修改

    当年naive的树套树题解

    前两天由于要讲整体二分,所以自己YY出了这种带修改的整体二分写法:

    由于每次插入的权值时固定的,因此可以把修改和询问放到一起整体二分。

    设 $solve(b,e,l,r)$ 表示解决 $[b,e]$ 中的修改和询问,其中:修改的权值、询问的答案都在 $[l,r]$ 内。

    那么如果 $l=r$ ,则区间内所有询问的答案都等于 $l$ 。

    否则设 $mid=frac{l+r}2$ ,然后按照时间序扫一遍修改和询问。

    对于修改:如果权值在 $[l,mid]$ 则丢到左区间,否则给这段区间整体+1并丢到右区间。

    对于询问:如果区间和(实际含义为该次询问时区间内权值在 $[mid+1,r]$ 内的数的个数)大于等于询问的 $c$ ,说明 $[mid+1,r]$ 内有足够多的数,答案在 $[mid+1,r]$ 内,丢到右区间;否则把 $c$ 减去这个区间和,并丢到左区间。

    清空数据结构,递归左右区间。注意对于左右区间也需要维护时间序。

    需要实现:区间修改、区间求和,可以使用树状数组区间修改实现。具体可以参考 【bzoj3132】上帝造题的七分钟

    时间复杂度 $O(nlog^2n)$ ,比树套树快了10倍多。。。(当然也有可能是我当年写的不好吧)

    注意本题爆int,因此需要unsigned int(比long long略快)。

    #include <cstdio>
    #define N 50010
    typedef unsigned int uint;
    struct data
    {
    	int opt , a , b , c , id;
    }q[N] , t[N];
    int flag[N] , ans[N] , n;
    struct bit
    {
    	uint v[N];
    	inline void add(int x , int a)
    	{
    		int i;
    		for(i = x ; i <= n ; i += i & -i) v[i] += a;
    	}
    	inline uint query(int x)
    	{
    		int i;
    		uint ans = 0;
    		for(i = x ; i ; i -= i & -i) ans += v[i];
    		return ans;
    	}
    }A , B;
    inline void modify(int x , int a)
    {
    	A.add(x , a) , B.add(x , a * x);
    }
    inline uint ask(int x)
    {
    	return (x + 1) * A.query(x) - B.query(x);
    }
    void solve(int b , int e , int l , int r)
    {
    	if(l == r)
    	{
    		int i;
    		for(i = b ; i <= e ; i ++ )
    			if(q[i].opt == 2)
    				ans[q[i].id] = l;
    		return;
    	}
    	int mid = (l + r) >> 1 , i , lp = b - 1 , rp = e + 1;
    	uint v;
    	for(i = b ; i <= e ; i ++ )
    	{
    		if(q[i].opt == 1)
    		{
    			if(q[i].c > mid) modify(q[i].a , 1) , modify(q[i].b + 1 , -1) , t[--rp] = q[i];
    			else t[++lp] = q[i];
    		}
    		else
    		{
    			v = ask(q[i].b) - ask(q[i].a - 1);
    			if((uint)q[i].c <= v) t[--rp] = q[i];
    			else q[i].c -= v , t[++lp] = q[i];
    		}
    	}
    	for(i = b ; i <= e ; i ++ )
    		if(q[i].opt == 1 && q[i].c > mid)
    			modify(q[i].a , -1) , modify(q[i].b + 1 , 1);
    	for(i = b ; i <= lp ; i ++ ) q[i] = t[i];
    	for(i = rp ; i <= e ; i ++ ) q[i] = t[e + rp - i];
    	solve(b , lp , l , mid) , solve(rp , e , mid + 1 , r);
    }
    int main()
    {
    	int m , i;
    	scanf("%d%d" , &n , &m);
    	for(i = 1 ; i <= m ; i ++ )
    	{
    		scanf("%d%d%d%d" , &q[i].opt , &q[i].a , &q[i].b , &q[i].c) , q[i].id = i;
    		if(q[i].opt == 2) flag[i] = 1;
    	}
    	solve(1 , m , -n , n);
    	for(i = 1 ; i <= m ; i ++ )
    		if(flag[i])
    			printf("%d
    " , ans[i]);
    	return 0;
    }
    

     

  • 相关阅读:
    supervisor管理airflow
    airflow迁移
    flume部署
    canal原理&部署
    EMR日常操作
    linux的route
    autossh
    Velocity(5)——#macro 指令
    Git(1)----Eclipse安装Git插件
    Velocity(4)——引入指令和#Parse 指令
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/8092824.html
Copyright © 2020-2023  润新知