zoukankan      html  css  js  c++  java
  • CodeForces 390E Inna and Large Sweet Matrix(树状数组改段求段)

    树状数组仅仅能实现线段树区间改动和区间查询的功能,能够取代不须要lazy tag的线段树。且代码量和常数较小

    首先定义一个数组 int c[N]; 并清空 memset(c, 0, sizeof c);

    1、单点改动 : c[x] += y; 相应的函数是 change(x, y);

    2、求前缀和 :  相应的函数是 int sum(x)

    两种操作的复杂度都是O(logn)

    模板例如以下:

    int c[N], maxn;  
    inline int Lowbit(int x){return x&(-x);}  
    void change(int i, int x)//i点增量为x  
    {  
        while(i <= maxn)  
        {  
            c[i] += x;  
            i += Lowbit(i);  
        }  
    }  
    int sum(int x){//区间求和 [1,x]  
        int ans = 0;  
        for(int i = x; i >= 1; i -= Lowbit(i))  
            ans += c[i];  
        return ans;  
    }  

    怎样运用树状数组进行区间操作

    先定义两个树状数组 X, Y

    如今我们须要对一个数组 int a[N]; 进行区间操作:[L, R] += val 即 for i:L to R a[i] += val; 

    再定义一个 int size = R-L+1 , 即区间长度

    相应的改动是 

    1、X[L] += val;   X[R+1] -= val;

    2、Y[L] += -1 * val * (L-1);   Y[R+1] += val * R;

    相应的查询是

    当我们求和  时在树状数组中操作是 ans = X.sum(k) * k + Y.sum(k)

    分类讨论一下k分别在 [1,L-1] , [L, R] , [R+1, +]

    1、k[1,L-1]  

    显然 X.sum(k) == 0 且 Y.sum(k) == 0 -> ans = X.sum(k)*k + Y.sum(k) = 0*i+0 = 0 结果与实际相符。

    2、k[L, R] 

    X.sum(k) * k = X[L] * k = val * k,   Y.sum(k) = Y[L] =  -1 * val * (L-1) 

    ans = val * k - val * (L-1) = val * ( k - (L-1) ); 

    3、k[R+1, ]

    X.sum(k) * k = ( x[L] + x[R] ) * k = 0 * k = 0;

    Y.sum(k) = Y[L] + Y[R] = -val * (L-1) + val * R = val * (R-L+1) = val * size

    X.sum(k) * k + Y.sum(k) = val * size

    证明完成。

    下面模版中两个树状数组c[0], c[1] 相应上述的X, Y

    区间改动:add(L, R, val)

    求 int a[N]的前缀和 get_pre(R)

    区间查询:get(L,R)

    const int N = 4e5 + 100;
    template<class T>
    struct Tree{
    	T c[2][N];
    	int maxn;
    	void init(int x){
    		maxn = x+10; memset(c, 0, sizeof c);
    	}
    	inline int lowbit(int x){ return x&-x; }
    	T sum(T *b, int x){
    		T ans = 0;
    		if (x == 0)ans = b[0];
    		while (x)ans += b[x], x -= lowbit(x);
    		return ans;
    	}
    	void change(T *b, int x, T value){
    		if (x == 0)b[x] += value, x++;
    		while (x <= maxn)b[x] += value, x += lowbit(x);
    	}
    	T get_pre(int r){
    		return sum(c[0], r) * r + sum(c[1], r);
    	}
    	void add(int l, int r, T value){//区间加权
    		change(c[0], l, value);
    		change(c[0], r + 1, -value);
    		change(c[1], l, value * (-l + 1));
    		change(c[1], r + 1, value * r);
    	}
    	T get(int l, int r){//区间求和
    		return get_pre(r) - get_pre(l - 1);
    	}
    };
    Tree<ll> tree;

    好了,回归正题,我们来讲一下这道题的题意:

    题意:给定n*m的二维平面 w个操作

    int mp[n][m] = { 0 };

    1、0 (x1,y1) (x2,y2) value

    for i : x1 to x2

    for j : y1 to y2 

    mp[i][j] += value;

    2、1 (x1, y1) (x2 y2)

    ans1 = 纵坐标在 y1,y2间的总数

    ans2 = 横坐标不在x1,x2间的总数

    puts(ans1-ans2);

    代码例如以下:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    
    typedef long long ll;
    const int N = 4e6+10;
    int n, m, w;
    template<class T>  
    struct Tree
    {  
        ll c[2][N];  
        int maxn;  
        void init(int x)
    	{  
            maxn = x+10; memset(c, 0, sizeof c);  
        }  
        inline int lowbit(int x)
    	{ 
    		return x&-x; 
    	}  
        ll sum(ll *b, int x)
    	{  
            ll ans = 0;  
            if (x == 0)ans = b[0];  
            while (x)ans += b[x], x -= lowbit(x);  
            return ans;  
        }  
        void change(ll *b, int x, ll value)
    	{  
            if (x == 0)b[x] += value, x++;  
            while (x <= maxn)b[x] += value, x += lowbit(x);  
        }  
        ll get_pre(int r)
    	{  
            return sum(c[0], r) * r + sum(c[1], r);  
        }  
        void add(int l, int r, ll value)
    	{  
            change(c[0], l, value);  
            change(c[0], r + 1, -value);  
            change(c[1], l, value * (-l + 1));  
            change(c[1], r + 1, value * r);  
        }  
        ll get(int l, int r)
    	{  
            return get_pre(r) - get_pre(l - 1);  
        }  
    };
      
    Tree<ll> x, y;  
    
    int main()
    {
    	scanf("%d%d%d", &n, &m, &w);
    	 x.init(n); y.init(m); 
    	int tmp;
    	ll all = 0;
    	while(w--)
    	{
    		scanf("%d", &tmp);
    		int x1, x2, y1, y2, v;
    		if(tmp == 0)
    		{
    			scanf("%d%d%d%d%d", &x1, &y1, &x2, &y2, &v);
    			all += v * (x2-x1+1) * (y2-y1+1);
    			x.add(x1, x2, v * (y2 - y1 + 1));
    			y.add(y1, y2, v * (x2 - x1 + 1));
    		}
    		if(tmp == 1)
    		{
    			scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
    			printf("%I64d
    ", y.get(1, y2) - y.get(1, y1-1) - (all - x.get(1, x2) + x.get(1, x1 - 1)));	
    		}
    	}
    	return 0;
    }
    







  • 相关阅读:
    Aurora 数据库支持多达五个跨区域只读副本
    Amazon RDS 的 Oracle 只读副本
    Amazon EC2 密钥对
    DynamoDB 读取请求单位和写入请求单位
    使用 EBS 优化的实例或 10 Gb 网络实例
    启动 LAMP 堆栈 Web 应用程序
    AWS 中的错误重试和指数退避 Error Retries and Exponential Backoff in AWS
    使用 Amazon S3 阻止公有访问
    路由表 Router Table
    使用MySQLAdmin工具查看QPS
  • 原文地址:https://www.cnblogs.com/mthoutai/p/6780958.html
Copyright © 2011-2022 走看看