hdu 1754 I Hate It
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1754
题目分析:二十万*五千的数据量,暴力就不要想了。这是个线段树入门水题,线段树是一种使用二叉树实现的奇特的数据结构,所以也具备了二叉树化N为lgN的能力,主要用来处理对一段区间上的特征值(如max、min等)的查询,是ACMer们数据结构方向上的必修课之一。此题甚水,只要懂线段树的基本知识,就能做了,具体可以参考我参考的那篇blog↓↓。
code:
#include<stdio.h>
#define inf 0x7fffffff
#define minf 0x80000000
struct stNode
{//left&right代表区间范围,此例程专门用作最大值与最小值的查询
int left,right,max,min;
}stn[600000];//树数组,记录方法同堆
int parent[210000];//记录各叶子节点在树数组中的位置
int max(int a,int b)
{
return a>b?a:b;
}
int min(int a,int b)
{
return a<b?a:b;
}
void build_tree(int i,int left,int right)
{
stn[i].left=left;
stn[i].right=right;
if(left==right)
{
parent[left]=i;
return;
}
build_tree(i<<1,left,(left+right)/2);
build_tree((i<<1)+1,(left+right)/2+1,right);//此处教训:左右移运算符的优先级低于算术运算(+)
}
void update_tree(int ri)
{
if(ri==1)return;
int fi=ri/2;
int a=fi*2,b=fi*2+1;
int maxi=max(stn[a].max,stn[b].max),mini=min(stn[a].min,stn[b].min);
stn[fi].max=maxi;
stn[fi].min=mini;
update_tree(ri/2);
}
int query(int i,int l,int r,bool flag)//i为当前节点号,lr为待查左右区间,flag为找最大/小值:true/false
{
if(stn[i].left>r||stn[i].right<l)return flag?minf:inf;//边界控制
if(l==r||stn[i].max==stn[i].min)return stn[i].max;//到了单个点,max==min。
if(stn[i].left>=l&&stn[i].right<=r)
{
return flag?stn[i].max:stn[i].min;
}
if(flag)return max(query(i<<1,l,r,flag),query((i<<1)+1,l,r,flag));
else return min(query(i<<1,l,r,flag),query((i<<1)+1,l,r,flag));
}
int main()
{
int i,n,m,a[210000],p,q;
char c[10];
while(scanf("%d%d",&n,&m)!=EOF)
{
build_tree(1,1,n);
for(i=1;i<=n;i++)
{
scanf("%d",a+i);
stn[parent[i]].max=stn[parent[i]].min=a[i];
update_tree(parent[i]);
}
while(m--)
{
scanf("%s%d%d",c,&p,&q);
if(c[0]=='Q')printf("%d\n",query(1,p,q,true));
else
{
stn[parent[p]].max=stn[parent[p]].min=q;
update_tree(parent[p]);
}
}
//for(i=0;i<=9;i++)
//{
//printf("node[%d]:left=%d,right=%d,max=%d,min=%d\n",i,stn[i].left,stn[i].right,stn[i].max,stn[i].min);
//}
}
return 0;
}
PS:参考了x314542916大神的blog,感谢赐教!
http://blog.csdn.net/x314542916/article/details/7837276
PSS:最难的query部分是我凭一己之力写的哦~