10.25T2 二维线段树

Description

  为了准备校庆庆典,学校招募了一些学生组成了一个方阵,准备在庆典上演出。
  这个方阵是一个n*m的矩形,第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,每个询问的方阵的长不超过宽的两倍。
 
 
 
 
二维线段树的板子。。。emmmm(好难写啊)
code:
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<string>
  4 #define lc (p<<1)
  5 #define rc (p<<1|1)
  6 #define N 3301
  7 #define max(i,j) i>j?i:j
  8 #define min(i,j) i<j?i:j
  9 using namespace std;
 10 const int inf=0x3f3f3f3f;
 11 int MAX=0,MIN=9999999;
 12 int n,m;
 13 int g[801][801],sum[801][801];
 14 struct segY {
 15     struct node {
 16         int l,r,min,max;
 17         node() {
 18             min=9999999;
 19         }
 20     } t[N];
 21     int up,down;
 22     void pushup(int p) {
 23         t[p].max=max(t[lc].max,t[rc].max);
 24         t[p].min=min(t[lc].min,t[rc].min);
 25     }
 26     void build(int p,int l,int r) {
 27         t[p].l=l,t[p].r=r;
 28         if(l==r) {
 29             for(int i=down; i<=up; i++)t[p].max=max(t[p].max,g[i][l]),t[p].min=min(t[p].min,g[i][l]);
 30             return;
 31         }
 32         int mid=l+r>>1;
 33         build(lc,l,mid);
 34         build(rc,mid+1,r);
 35         pushup(p);
 36     }
 37     int query_max(int p,int ql,int qr) {
 38         if(ql<=t[p].l&&t[p].r<=qr) {
 39             return t[p].max;
 40         }
 41         int a1=0,a2=0;
 42         int mid=t[p].l+t[p].r>>1;
 43         if(ql<=mid)a1=query_max(lc,ql,qr);
 44         if(qr>mid)a2=query_max(rc,ql,qr);
 45         return a1>a2?a1:a2;
 46     }
 47     int query_min(int p,int ql,int qr) {
 48         if(ql<=t[p].l&&t[p].r<=qr) {
 49             return t[p].min;
 50         }
 51         int a1=inf,a2=inf;
 52         int mid=t[p].l+t[p].r>>1;
 53         if(ql<=mid)a1=query_min(lc,ql,qr);
 54         if(qr>mid)a2=query_min(rc,ql,qr);
 55         return a1>a2?a2:a1;
 56     }
 57 };
 58 struct segX {
 59     int l,r;
 60     segY Y;
 61 } t[800*4];
 62 void Build(int p,int l,int r) {
 63     t[p].l=l,t[p].r=r;
 64     t[p].Y.down=l,t[p].Y.up=r;
 65     t[p].Y.build(1,1,m);
 66     if(l==r)return;
 67     int mid=l+r>>1;
 68     Build(lc,l,mid);
 69     Build(rc,mid+1,r);
 70 }
 71 int Query_min(int p,int x1,int y1,int x2,int y2) {
 72     if(x1<=t[p].l&&t[p].r<=x2) {
 73         return t[p].Y.query_min(1,y1,y2);
 74     }
 75     int a1=inf,a2=inf;
 76     int mid=t[p].l+t[p].r>>1;
 77     if(x1<=mid)a1=Query_min(lc,x1,y1,x2,y2);
 78     if(x2>mid)a2=Query_min(rc,x1,y1,x2,y2);
 79     return a1>a2?a2:a1;
 80 }
 81 int Query_max(int p,int x1,int y1,int x2,int y2) {
 82     if(x1<=t[p].l&&t[p].r<=x2) {
 83         return t[p].Y.query_max(1,y1,y2);
 84     }
 85     int a1=0,a2=0;
 86     int mid=t[p].l+t[p].r>>1;
 87     if(x1<=mid)a1=Query_max(lc,x1,y1,x2,y2);
 88     if(x2>mid)a2=Query_max(rc,x1,y1,x2,y2);
 89     return a1<a2?a2:a1;
 90 }
 91 long long read() {
 92     long long x=0,f=1;
 93     char c=getchar();
 94     while(!isdigit(c)) {
 95         if(c=='-')f=-1;
 96         c=getchar();
 97     }
 98     while(isdigit(c)) {
 99         x=(x<<3)+(x<<1)+c-'0';
100         c=getchar();
101     }
102     return x*f;
103 }
104 int main() {
105     n=read(),m=read();
106     for(int i=1; i<=n; i++) {
107         for(int j=1; j<=m; j++) {
108             g[i][j]=read();
109             sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+g[i][j];
110         }
111     }
112     Build(1,1,n);
113     int Q;
114     Q=read();
115     char opt[5];
116     while(Q--) {
117         scanf("%s",opt);
118         if(opt[1]=='U') {
119             int x1,x2,y1,y2;
120             x1=read(),y1=read(),x2=read(),y2=read();
121             x1++,x2++,y1++,y2++;
122             cout<<sum[x2][y2]-sum[x1-1][y2]-sum[x2][y1-1]+sum[x1-1][y1-1]<<'\n';
123         }
124         if(opt[1]=='A') {
125             int x1,x2,y1,y2;
126             x1=read(),y1=read(),x2=read(),y2=read();
127             x1++,x2++,y1++,y2++;
128             cout<<Query_max(1,x1,y1,x2,y2)<<'\n';
129         }
130         if(opt[1]=='I') {
131             int x1,x2,y1,y2;
132             x1=read(),y1=read(),x2=read(),y2=read();
133             x1++,x2++,y1++,y2++;
134             cout<<Query_min(1,x1,y1,x2,y2)<<'\n';
135         }
136     }
137     return 0;
138 }

over

转载于:https://www.cnblogs.com/saionjisekai/p/9852313.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值