UVA-11992(线段树)

题意

对矩阵有三种操作,第一是让矩阵的每个元素加上某个数,第二是让矩阵得每个元素变成某个数,第三是输出某个子矩阵的数字总和,最大值和最小值。开始时,矩阵得每个元素为0.

思路

因为最多只有20行,所以可以每行都建立一个线段树,问题是注意set操作和add操作之间的联系,set是优先于add的。我在pushdown函数中就因为没注意这个问题,WA到怀疑人生。

#include<bits/stdc++.h>
using namespace std;
const int N = 501000;
struct Node{
    int sum,mini,maxi,add,seti;
}tree[21][N << 2];
const int inf = 0x3f3f3f3f;
int miner,maxer,sum;
void maketree(int node,int begin,int end, Node tree[])
{
    tree[node].add = 0;
    tree[node].seti = 0;
    if(begin == end)
    {
        tree[node].mini = tree[node].maxi = tree[node].sum = 0;
        return;
    }
    int mid = (begin + end) / 2;
    maketree(node << 1,begin,mid ,tree);
    maketree(node << 1|1,mid + 1,end ,tree);
    tree[node].maxi = tree[node].mini = tree[node].seti = 0;
}
void pushdown(int node,int begin,int end,Node tree[])
{
     if(tree[node].seti != 0)
    {
        int mid = ( begin + end) / 2;
        tree[node << 1].sum = (mid - begin + 1) * tree[node].seti;
        tree[node << 1 | 1].sum = (end - mid) * tree[node].seti;
        tree[node << 1].add = tree[node].seti;
        tree[node << 1|1].add = tree[node].seti;
        tree[node << 1].maxi = tree[node].seti;
        tree[node << 1|1].maxi = tree[node].seti;
        tree[node << 1].mini = tree[node].seti;
        tree[node << 1|1].mini = tree[node].seti;
        tree[node << 1].add = tree[node << 1|1].add = 0;
        tree[node << 1].seti = tree[node << 1|1].seti = tree[node].seti;
        tree[node].seti = 0;
    }
    if(tree[node].add != 0)
    {
        int mid = ( begin + end) / 2;
        tree[node << 1].sum += (mid - begin + 1) * tree[node].add;
        tree[node << 1 | 1].sum += (end - mid) * tree[node].add;
        tree[node << 1].add += tree[node].add;
        tree[node << 1|1].add += tree[node].add;
        tree[node << 1].maxi += tree[node].add;
        tree[node << 1|1].maxi += tree[node].add;
        tree[node << 1].mini += tree[node].add;
        tree[node << 1|1].mini += tree[node].add;
        tree[node].add = 0;
    }
}
void add(int node,int begin,int end,int l,int r ,int v,Node tree[])
{
    if(l > end || r < begin )
        return ;
    if(begin >= l && end <= r)
    {
       tree[node].sum += (end - begin + 1)* v;
       tree[node].maxi += v;
       tree[node].mini += v;
       tree[node].add += v;
       return;
    }
    pushdown(node,begin,end,tree);
    int mid = (begin  + end) / 2;
    add(node << 1,begin,mid ,l,r,v,tree);
    add(node << 1|1,mid + 1, end,l,r,v,tree);
    tree[node].maxi = max(tree[node << 1].maxi,tree[node << 1|1].maxi);
    tree[node].mini = min(tree[node << 1].mini,tree[node << 1|1].mini);
    tree[node].sum = tree[node << 1].sum + tree[node << 1|1].sum;
}
void seti(int node,int begin,int end,int l,int r,int v,Node tree[])
{
    if(l > end || r < begin)
        return;
    if(begin >= l && end <= r)
    {
       tree[node].sum = (end - begin + 1) * v;
       tree[node].maxi = v;
       tree[node].mini = v;
       tree[node].add = 0;
       tree[node].seti = v;
       return;
    }
    pushdown(node,begin,end,tree);
    int mid = (begin  + end) / 2;
    seti(node << 1,begin,mid ,l,r,v,tree);
    seti(node << 1|1,mid + 1, end,l,r,v,tree);
    tree[node].maxi = max(tree[node << 1].maxi,tree[node << 1|1].maxi);
    tree[node].mini = min(tree[node << 1].mini,tree[node << 1|1].mini);
    tree[node].sum = tree[node << 1].sum + tree[node << 1|1].sum;
}
void query(int node,int begin ,int end,int l,int r,Node tree[])
{
    if(l > end || r < begin )
        return;
    if(l <= begin && r >= end)
    {
        miner = min(miner,tree[node].mini);
        maxer = max(maxer,tree[node].maxi);
        sum +=  tree[node].sum;
        return;
    }
    pushdown(node,begin,end,tree);
    int mid = (begin + end) / 2;
    query(node << 1,begin ,mid ,l, r ,tree);
    query(node << 1|1,mid + 1,end ,l,r ,tree);
}
int main()
{
     int n,m,k,i,x1,y1,y2,x2,v,A,j;
     while(~scanf("%d %d %d",&n,&m,&k))
     {
     for(i = 1; i <= n ;i++)
        maketree(1,1,m,tree[i]);
     for(j = 1; j <= k ; j++)
     {
         scanf("%d",&A);
         if(A == 1)
         {
             scanf("%d %d %d %d %d",&x1,&y1,&x2,&y2,&v);
             for(i = x1; i <= x2 ;i++ )
             {
                 add(1,1,m,y1,y2,v,tree[i]);
             }
         }
         else if(A == 2)
         {
             scanf("%d %d %d %d %d",&x1,&y1,&x2,&y2,&v);
             for(i = x1 ;i <= x2 ;i++)
             {
                 seti(1,1,m,y1,y2,v,tree[i]);
             }
         }
         else if(A == 3)
         {
             scanf("%d %d %d %d",&x1,&y1,&x2,&y2);
             miner = inf;
             maxer = -1;
             sum = 0;
             for(i = x1 ;i <= x2 ;i++)
             {
                 query(1,1,m,y1,y2,tree[i]);
             }
             printf("%d %d %d\n",sum,miner,maxer);
         }
     }
     }
     return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值