UVA 11992 Fast Matrix Operations 线段树

大致题意:给你一个r*c的矩阵,r*c<=1e6,给你三种操作,第一种,1 x1 y1 x2 y2 u ,把[x1,y1,x2,y2]子矩阵所有的元素都加上u,第二种,2 x1 y1 x2 y2 u,把[x1,y1,x2,y2]子矩阵的所有元素变成u,第三种,3 x1 y1 x2 y2,查询[x1,y1,x2,y2]所有元素的和,最大值,最小值。
思路:开始并不知道怎么搞,直到发现了r<=20之后,直接暴力好了,反正一个查询或更新的复杂度也就20*log(N)
坑点:是我没想好,第二种操作会对第一种操作有影响,具体就是第二种操作的时候会抵消第一种操作之前所做的状态。所以要处理一下。

http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=18697

#include <cstdio>
#include <cmath>
#include <iostream>

#define change(x,y) (x-1)*clo+y
#define dist(rt) (t[rt].y - t[rt].x + 1)

using namespace std;

const int MAXN = 1e6+5;

struct Node {
    int x,y;
    int add,live; //add代表这个区间加上的值,live表示把这个区间所有值变成live;
    int minnum,maxnum; //minnum 区间最小,区间最大;
    int sum; //区间内总和;
}t[MAXN<<2];

int n,m;
int row,clo;

void Push_Up(int rt) {
    t[rt].sum = t[rt<<1].sum + t[rt<<1|1].sum;
    t[rt].maxnum = max(t[rt<<1].maxnum,t[rt<<1|1].maxnum);
    t[rt].minnum = min(t[rt<<1].minnum,t[rt<<1|1].minnum);
}

void Push_Down(int rt) {
    if(t[rt].live) {
        t[rt<<1].sum = dist(rt<<1) * t[rt].live;
        t[rt<<1|1].sum = dist(rt<<1|1) * t[rt].live;
        t[rt<<1].maxnum = t[rt].live; t[rt<<1|1].maxnum = t[rt].live;
        t[rt<<1].minnum = t[rt].live; t[rt<<1|1].minnum = t[rt].live;
        t[rt<<1].live = t[rt<<1|1].live = t[rt].live;
        t[rt<<1].add  = t[rt<<1|1].add  = 0;//去掉live 对 add的影响,之前add的要全部取消掉
        t[rt].live = 0;
    }
    if(t[rt].add) {
        t[rt<<1].sum += dist(rt<<1) * t[rt].add;
        t[rt<<1|1].sum += dist(rt<<1|1) * t[rt].add;
        t[rt<<1].maxnum += t[rt].add; t[rt<<1|1].maxnum += t[rt].add;
        t[rt<<1].minnum += t[rt].add; t[rt<<1|1].minnum += t[rt].add;
        t[rt<<1].add += t[rt].add; t[rt<<1|1].add += t[rt].add;
        t[rt].add = 0;
    }

}

void Build(int x,int y,int rt) {
    t[rt].x = x; t[rt].y = y;
    t[rt].add = t[rt].live = 0;
    if(x == y) {
        t[rt].sum = 0;
        t[rt].maxnum = 0;
        t[rt].minnum = 0;
        return ;
    }
    int mid = (x + y) >> 1;
    Build(x,mid,rt<<1);
    Build(mid+1,y,rt<<1|1);
    Push_Up(rt);
}

void Update(int rt,int left,int right,int u,int flag) {
    if(t[rt].x >= left && t[rt].y <= right) {
        if(flag) {
            t[rt].sum += dist(rt) * u;
            t[rt].add += u;
            t[rt].maxnum += u;
            t[rt].minnum += u;
        }
        else {
            t[rt].sum = dist(rt) * u;
            t[rt].live = u;
            t[rt].add = 0;//去掉live 对 add的影响,之前add的要全部取消掉
            t[rt].maxnum = u;
            t[rt].minnum = u;
        }
        return ;
    }
    int mid = (t[rt].x + t[rt].y) >> 1;
    Push_Down(rt);
    if(mid >= left) Update(rt<<1,left,right,u,flag);
    if(mid < right) Update(rt<<1|1,left,right,u,flag);
    Push_Up(rt);
}

int sum ;
int maxnum , minnum;

void Query(int rt,int left,int right) {
    if(t[rt].x >= left && t[rt].y <= right) {
        sum += t[rt].sum;
        maxnum = max(maxnum,t[rt].maxnum);
        minnum = min(minnum,t[rt].minnum);
        return ;
    }
    int mid = (t[rt].x + t[rt].y) >> 1;
    Push_Down(rt);
    if(mid >= left) Query(rt<<1,left,right);
    if(mid < right) Query(rt<<1|1,left,right);
    Push_Up(rt);
}

void Print_Tree(int rt) {
    static int cnt = 0;
    Push_Down(rt);
    if(t[rt].x == t[rt].y) {
        cnt ++;
        if(cnt % 4 == 0) {
            printf("%d\n",t[rt].sum);
        }
        else {
            printf("%d ",t[rt].sum);
        }
        return ;
    }
    Print_Tree(rt<<1);
    Print_Tree(rt<<1|1);
}

void input() {
    Build(1,change(row,clo),1);
    int ok,u;
    int x1,y1,x2,y2;
    for(int i = 1 ; i <= n ; i ++) {
        //Print_Tree(1);
        scanf("%d %d %d %d %d",&ok,&x1,&y1,&x2,&y2);
        if(ok == 1) {
            scanf("%d",&u); //add 
            for(int j = x1 ; j <= x2 ; j ++) {
                Update(1,change(j,y1),change(j,y2),u,1);
            }
        }
        else if(ok == 2) { //live
            scanf("%d",&u);
            for(int j = x1 ; j <= x2 ; j ++) {
                Update(1,change(j,y1),change(j,y2),u,0);
            }
        }
        else {
            sum = 0;
            minnum = 0x3f3f3f3f;
            maxnum = 0;
            for(int j = x1 ; j <= x2 ; j ++) {
                Query(1,change(j,y1),change(j,y2));
            }
            printf("%d %d %d\n",sum,minnum,maxnum);
        }
    }
}

void solve() {

}

int main(void) {
    //freopen("a.in","r",stdin);
    while(~scanf("%d %d %d",&row,&clo,&n)) {
        input();
        solve();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值