您的位置:首页 > 理论基础 > 计算机网络

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.

样例输入
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐