• 方阵-二维线段树


    Description

      为了准备校庆庆典,学校招募了一些学生组成了一个方阵,准备在庆典上演出。
      这个方阵是一个nm的矩形,第i行第j列有一名学生,他有一个能力值Ai,j。
      校长会定期检查一个p
    q的方阵,询问这个方阵的学生能力值之和,或是学生能力值的最大值,或是学生能力值的最小值。由于校长不喜欢一个方阵长宽之比差太多,他每次询问的方阵的长不会超过宽的两倍。作为校庆筹办组组长的你,应该迅速并准确的回答校长所问的问题。

    Input

      第一行包含两个整数n,m,表示这个方阵的两条边的长度。
      接下来n行,每行m个数,表示每个学生的能力值。
      接下来一行包含一个整数q,表示校长的询问数。
      接下来q行,每行先一个字符串s,接下来4个整数x1,y1,x2,y2,保证x1≤x2,y1≤y2,设以第x1行y1列为左上角,第x2行y2列为右下角的方阵为P。(本题为0下标)
      若字符串内容为“SUM”,请求出P中所有学生的能力值之和。
      若字符串内容为“MAX”,请求出P中所有学生的能力值的最大值。
      若字符串内容为“MIN”,请求出P中所有学生的能力值的最小值。

    Output

      输出总共q行,第i行的数为第i组询问对应的答案ansi。

    Sample Input

    3 3
    1 2 3
    4 5 6
    7 8 9
    3
    SUM 0 0 1 1
    MAX 0 0 2 2
    MIN 0 1 1 1

    Sample Output

    12
    9
    2

    Hint

    【样例解释】
      对于第一组询问,能力值之和为1+2+4+5=12。
      对于第二组询问,能力值最大的位置为第2行第2列。
      对于第三组询问,能力值最小的位置为第0行第1列。
    【数据规模和约定】
      对于40%的数据,n,m≤200,q≤200
      对于60%的数据,n,m≤300,q≤100000
      对于80%的数据,n,m≤500,q≤500000
      对于100%的数据,n,m≤800,q≤500000,0≤Aij≤3000,每个询问的方阵的长不超过宽的两倍。


    思路

    • 二维线段树或二维RMQ模板
    • 代码为二维线段树

    代码

    #include <iostream>
    #include <cstdio>
    using namespace std;
    const int inf=3005;
    const int maxn=802;
    int n,m,q,sum[maxn][maxn],ansmax,ansmin;
    struct node_y{short maxx,minn,l,r;};
    struct node_x{node_y f[maxn<<2];short l,r;}a[maxn<<2];
    short max(short a,short b){return a>b?a:b;}
    short min(short a,short b){return a<b?a:b;}
    void pushup_y(int x,int v) {
    	a[v].f[x].maxx=max(a[v].f[x<<1].maxx,a[v].f[x<<1|1].maxx);
    	a[v].f[x].minn=min(a[v].f[x<<1].minn,a[v].f[x<<1|1].minn);
    }
    void pushup_x(int x,int v){
    	a[v].f[x].maxx=max(a[v<<1].f[x].maxx,a[v<<1|1].f[x].maxx);
    	a[v].f[x].minn=min(a[v<<1].f[x].minn,a[v<<1|1].f[x].minn);
    }
    void build_y(int x,int left,int right,int v,int lx)
    {
    	a[v].f[x].l=left; a[v].f[x].r=right;
    	if(left==right) {
    		if(lx!=-1) a[v].f[x].maxx=a[v].f[x].minn=sum[lx][left];
    		else pushup_x(x,v);
    		return;
    	}
    	int mid=(left+right)>>1;
    	build_y(x<<1,left,mid,v,lx); build_y(x<<1|1,mid+1,right,v,lx);
    	pushup_y(x,v);
    }
    void build_x(int x,int left,int right)
    {
    	a[x].l=left; a[x].r=right; 
    	if(left==right) {build_y(1,1,m,x,left); return;}
    	int mid=(left+right)>>1;
    	build_x(x<<1,left,mid); build_x(x<<1|1,mid+1,right);
    	build_y(1,1,m,x,-1);
    }
    void query_y(int x,int left,int right,int v)
    {
    	if(a[v].f[x].r<left||a[v].f[x].l>right) return;
    	if(left<=a[v].f[x].l&&right>=a[v].f[x].r){
    		ansmax=max(ansmax,a[v].f[x].maxx);
    		ansmin=min(ansmin,a[v].f[x].minn);
    		return;
    	}
    	query_y(x<<1,left,right,v); query_y(x<<1|1,left,right,v);
    }
    void query_x(int x,int xl,int xr,int yl,int yr)
    {
    	if(a[x].r<xl||a[x].l>xr) return;
    	if(xl<=a[x].l&&xr>=a[x].r){query_y(1,yl,yr,x); return;}
    	query_x(x<<1,xl,xr,yl,yr); query_x(x<<1|1,xl,xr,yl,yr);
    }
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<=m;++j) scanf("%d",&sum[i][j]);
    	build_x(1,1,n);
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<=m;++j) sum[i][j]+=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1];
    	scanf("%d",&q);
    	while(q--)
    	{
    		char f[5]; int t1,t2,t3,t4; scanf("%s%d%d%d%d",&f,&t1,&t2,&t3,&t4); ++t1;++t2;++t3;++t4;
    		if(f[0]=='S') cout<<sum[t3][t4]-sum[t3][t2-1]-sum[t1-1][t4]+sum[t1-1][t2-1]<<'
    ';
    		else if(f[1]=='A') ansmax=-inf,query_x(1,t1,t3,t2,t4),cout<<ansmax<<'
    ';
    		else ansmin=inf,query_x(1,t1,t3,t2,t4),cout<<ansmin<<'
    ';
    	}
    	return 0;
    }
    
  • 相关阅读:
    Centos7 一键脚本离线安装 Docker-18.03.1-ce
    RedHat 6.8 离线安装Docker (rpm包安装)
    extends和implements区别
    chrome浏览器 同站(SameSite)策略 导致 iframe 内嵌页面cookie无法写入
    快速删除node_modules文件夹:rimraf
    Antd中InputNumber组件数字限制小数位数
    慧聪网如何注册
    2020年9月至10月 Splashtop 新功能
    远程桌面软件的5个首要功能
    Splashtop和 TiFlux 宣布建立合作伙伴关系
  • 原文地址:https://www.cnblogs.com/wuwendongxi/p/14056283.html
Copyright © 2020-2023  润新知