ICPC2017网络赛(北京)Minimum(线段树or树状数组区间最值维护)
2017-09-24 11:38
459 查看
参考讲解:https://hihocoder.com/problemset/problem/1586
树状数组位数区间最值(单点修改+区间最值查询)
You are given a list of integers a0, a1,
…, a2^k-1.
You need to support two types of queries:
1. Output Minx,y∈[l,r] {ax∙ay}.
2. Let ax=y.
The first line is an integer T, indicating the number of test cases. (1≤T≤10).
For each test case:
The first line contains an integer k (0 ≤ k ≤ 17).
The following line contains 2k integers, a0,
a1, …, a2^k-1 (-2k ≤
ai < 2k).
The next line contains a integer (1 ≤ Q < 2k), indicating the number of queries. Then next
Q lines, each line is one of:
1. 1 l r: Output Minx,y∈[l,r]{ax∙ay}.
(0 ≤ l ≤ r < 2k)
2. 2 x y: Let ax=y. (0 ≤ x <
2k, -2k ≤ y < 2k)
输出
For each query 1, output a line contains an integer, indicating the answer.
样例输入
样例输出
【树状数组代码】:
树状数组位数区间最值(单点修改+区间最值查询)
描述
You are given a list of integers a0, a1,…, a2^k-1.
You need to support two types of queries:
1. Output Minx,y∈[l,r] {ax∙ay}.
2. Let ax=y.
输入
The first line is an integer T, indicating the number of test cases. (1≤T≤10).For each test case:
The first line contains an integer k (0 ≤ k ≤ 17).
The following line contains 2k integers, a0,
a1, …, a2^k-1 (-2k ≤
ai < 2k).
The next line contains a integer (1 ≤ Q < 2k), indicating the number of queries. Then next
Q lines, each line is one of:
1. 1 l r: Output Minx,y∈[l,r]{ax∙ay}.
(0 ≤ l ≤ r < 2k)
2. 2 x y: Let ax=y. (0 ≤ x <
2k, -2k ≤ y < 2k)
输出
For each query 1, output a line contains an integer, indicating the answer.
样例输入
1 3 1 1 2 2 1 1 2 2 5 1 0 7 1 1 2 2 1 2 2 2 2 1 1 2
样例输出
1 1 4
【树状数组代码】:
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <algorithm> using namespace std; typedef long long ll; const int INF=0x3f3f3f3f; const int MAX=1<<18; struct tree{ int n; int a[MAX],Max[MAX],Min[MAX];//Max维护最大值 ,Min最小 void init(int N) { n=N; for(int i=0;i<=N;i++) Max[i]=-(Min[i]=INF); } void update(int x,int num)//单点更新 { a[x]=num; while(x<=n) { Min[x]=Max[x]=a[x]; int lx=x&-x; for(int i=1;i<lx;i<<=1) { Max[x]=max(Max[x],Max[x-i]); Min[x]=min(Min[x],Min[x-i]); } x+=x&-x; } } int Qmax(int x,int y)//[x,y]最大值 { int ans=-INF; while(y>=x) { ans=max(a[y], ans); y--; for(;y-(y&-y)>=x;y-=(y&-y)) ans=max(Max[y],ans); } return ans; } int Qmin(int x, int y) { int ans=INF; while(y>=x) { ans=min(a[y],ans); y--; for(;y-(y&-y)>= x; y-=(y&-y) ) ans=min(Min[y],ans); } return ans; } }C; int main() { int n,m,i,j,x,y,ch,T; cin>>T; while(T--) { scanf("%d",&n); n=(1<<n); C.init(n);//初始化 for (i=1;i<=n;i++) { scanf("%d",&y); C.update(i,y); } cin>>m; for (i=1; i<=m; i++) { scanf("%d%d%d",&ch,&x,&y); if (ch == 1) { int u=C.Qmax(x+1,y+1); int v=C.Qmin(x+1,y+1); ll ans; if(u<=0)ans=(ll)u*u; else if(v>=0)ans=v*v; else ans=(ll)u*v; printf("%lld\n",ans); } if(ch==2) C.update(x+1,y); } } return 0; }【线段树代码】:
#include<stdio.h> #include<stdlib.h> #include<string.h> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int MAX=220; const int INF=0x3f3f3f3f; int a[MAX+2],n; int sum[2*MAX],Min[2*MAX],Max[2*MAX]; void creat(int root=1,int l=1,int r=n) { if(l==r)//叶子节点 { sum[root]=a[l]; Max[root]=a[l]; Min[root]=a[l]; return; } int mid=(l+r)/2; creat(root*2,l,mid); //左子树的创建 creat(root*2+1,mid+1,r); //右子树 sum[root]=sum[root*2]+sum[root*2+1]; Max[root]=max(Max[root*2],Max[root*2+1]); Min[root]=min(Min[root*2],Min[root*2+1]); } void update(int kl,int kr,int num, int root=1,int l=1,int r=n)//区间[kl,kr]修改 { if(l==r){ a[l]=num; sum[root]=num; Max[root]=num; Min[root]=num; return; } int mid=(l+r)/2; if(kl<=mid) update(kl,kr,num,root*2,l,mid); if(kr>mid) update(kl,kr,num,root*2+1,mid+1,r); sum[root]=sum[root*2]+sum[root*2+1]; Max[root]=max(Max[root*2],Max[root*2+1]); Min[root]=min(Min[root*2],Min[root*2+1]); } int Qsum(int left,int right, int root=1,int l=1,int r=n)//区间和 { if(left<=l&&r<=right) return sum[root]; int mid=(l+r)/2; int t1=0,t2=0; if(left<=mid) t1=Qsum(left,right,root*2,l,mid);//区间在左子树 if(right>mid) t2=Qsum(left,right,root*2+1,mid+1,r);//在右子树 return t1+t2; } int Qmax(int left,int right, int root=1,int l=1,int r=n)//查询区间[left,right]的最大值 { if(left<=l&&r<=right) return Max[root]; int mid=(l+r)/2; int t1=-INF,t2=-INF; if(left<=mid) t1=Qmax(left,right,root*2,l,mid);//区间在左子树 if(right>mid) t2=Qmax(left,right,root*2+1,mid+1,r);//在右子树 return max(t1,t2); } int Qmin(int left,int right, int root=1,int l=1,int r=n)//查询区间[left,right]最小值 { if(left<=l&&r<=right) return Min[root]; int mid=(l+r)/2; int t1=INF,t2=INF; if(left<=mid) t1=Qmin(left,right,root*2,l,mid);//区间在左子树 if(right>mid) t2=Qmin(left,right,root*2+1,mid+1,r);//在右子树 return min(t1,t2); } int main() { int m,i,j,x,y,ch,T; cin>>T; while(T--) { scanf("%d",&n); n=(1<<n); for (i=1;i<=n;i++) { scanf("%d",&a[i]); } creat(1,1,n); cin>>m; for(i=1;i<=m;i++) { scanf("%d%d%d",&ch,&x,&y); if(ch==1) { int u=Qmax(x+1,y+1); int v=Qmin(x+1,y+1); ll ans; if(u<=0)ans=(ll)u*u; else if(v>=0)ans=(ll)v*v; else ans=(ll)u*v; printf("%lld\n",ans); } if(ch==2) update(x+1,x+1,y); } } return 0; }
相关文章推荐
- poj 3468 A Simple Problem with Integers(线段树区间更新 or 树状数组区间更新)
- 【Hihocoder 1167】 高等理论计算机科学 (树链的交,线段树或树状数组维护区间和)
- HDU - 1394 Minimum Inversion Number(树状数组 or 线段树)
- hdoj 1394 Minimum Inversion Number 【线段树 or 线段树lazy or 树状数组 or 归并排序】【逆序对】
- HDU 1166 敌兵布阵(树状数组 or 线段树 单点修改 区间求和)
- POJ 3468 A Simple Problem with Integers(线段树 or 树状数组—区间求和,成段更新)
- poj 3468 A Simple Problem with Integers (线段树区间更新 + 树状数组区间更新)
- hdoj 1556 Color the ball 【线段树 + lazy区间更新】 【树状数组】
- poj 2352 Stars(树状数组 or 线段树)
- zoj 1484 Minimum Inversion Number(树状数组||线段树)
- POJ2352 Stars 【树状数组】or【线段树】
- HDU 1556 Color the ball 很典型的更新区间查找点的题(线段树树状数组两种解法)
- hdu 1556 Color the ball(线段树 or 树状数组 or 前缀和)
- hdoj 1166 敌兵布阵 【单点更新+区间求和】 【线段树】 【树状数组】
- HDU 1394 Minimum Inversion Number(树状数组||线段树)
- HDU1556:Color the ball(线段树区间更新单点求值)&&树状数组解法
- HDU 4638 多校第四场1007 离线询问,树状数组||线段树维护
- POJ 2155 Matrix (二维线段树入门,成段更新,单点查询 / 二维树状数组,区间更新,单点查询)
- hdoj 1541 Stars 【树状数组 线段树】【单点更新 区间求和】
- HDU 1934 Minimum Inversion Number(树状数组,线段树)