啥叫线段树:http://dongxicheng.org/structure/segment-tree/
自己参考,自己查,要考软考,没时间,。。。
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1166
//Accepted 1166 46MS 2256K 2359 B C 丹明扬
#include <stdio.h>
#include <string.h>
#define M 500002
struct node
{
int left; //左边界
int right; //右边界
int mid; //在add或sub时,是加在左子树呢还是右子树呢
int num; //人数
} p[M];
void init(int a,int b,int n)
{
p[n].left = a;
p[n].right = b;
p[n].mid = (a+b)/2;
p[n].num = 0;
if(a + 1 == b) //当分的不能再分时,例如[0,1]
{
return ;
}
init(a,(a+b)/2,2*n); //n若从1开始,那么2*n就是左子树下标,左边界还是a,右边界取中值
init((a+b)/2,b,2*n+1); //同理,得右子树
}
void add(int pos,int value,int n)
{
p[n].num += value;
if(p[n].left + 1 == p[n].right)
return ;
if(pos < p[n].mid)
{
//加在左子树
add(pos,value,2*n);
}
else
{
add(pos,value,2*n + 1);
}
}
void sub(int pos,int value,int n)
{
p[n].num -= value;
if(p[n].left + 1 == p[n].right)
return ;
if(pos < p[n].mid)
sub(pos,value,2*n);
else
sub(pos,value,2*n + 1);
}
int query(int a,int b,int n)
{
if(p[n].left == a && p[n].right == b)
return p[n].num;
if(a < p[n].mid )
{
if(b <= p[n].mid )
{
return query(a,b,2*n);
}
else
{
return query(a,p[n].mid,2*n) + query(p[n].mid,b,2*n + 1);
}
}
else
return query(a,b,2*n+1);
}
int main()
{
int icase;
int N,i,va;
char c[10];
int ax,ay;
int times = 0;
scanf("%d",&icase);
while(icase --)
{
memset(c,0,sizeof(c));
scanf("%d",&N);
init(1,N+1,1);
for(i = 1; i <= N; i++)
{
scanf("%d",&va);
add(i,va,1);
}
printf("Case %d:\n",++times);
while(1)
{
scanf("%s",c);
if( !strcmp(c,"End"))
{
break;
}
scanf("%d%d",&ax,&ay);
if( strcmp(c,"Query") == 0)
{
printf ("%d\n",query(ax,ay+1,1));
}
else if(strcmp(c,"Add") == 0)
{
add(ax,ay,1);
}
else if(strcmp(c,"Sub") == 0)
{
sub(ax,ay,1);
}
}
}
return 0;
}
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1754
Accepted 1754 968MS 8420K 2025 B C 丹明扬
#include <stdio.h>
#include <string.h>
#define M 20000002
struct node
{
int left; //左边界
int right; //右边界
int mid; //在add或sub时,是加在左子树呢还是右子树呢
int score; //分数
} p[M];
int maxx(int a,int b)
{
return (a > b) ? a:b;
}
void init(int a,int b,int n)
{
p[n].left = a;
p[n].right = b;
p[n].mid = (a+b)/2;
p[n].score = -999;
if(a + 1 == b) //当分的不能再分时,例如[0,1]
{
return ;
}
init(a,(a+b)/2,2*n); //n若从1开始,那么2*n就是左子树下标,左边界还是a,右边界取中值
init((a+b)/2,b,2*n+1); //同理,得右子树
}
void update(int pos,int value,int n)
{
if(value > p[n].score)
p[n].score = value; //把pos所在位置都更新了,第一次肯定在[1,n]。。。然后,看在左还是右。。。
if(p[n].left + 1 == p[n].right)
return ;
if(pos < p[n].mid)
{
update(pos,value,2*n);
}
if(pos >= p[n].mid)
{
update(pos,value,2*n+1);
}
}
int query(int a,int b,int n)
{
if(p[n].left == a && p[n].right == b) //如果[a,b]为叶子节点
return p[n].score;
if(a < p[n].mid )
{
if(b <= p[n].mid)
return query(a,b,2*n);
else //a,b分在mid两侧,求最大的
return maxx( query(a,p[n].mid,2*n),query(p[n].mid,b,2*n+1) );
}
else
return query(a,b,2*n+1);
}
int main()
{
int n,m,t,a,b,i;
char ch;
while(scanf("%d %d",&n,&m) != EOF)
{
init(1,n+1,1);
for(i = 1; i <= n; i++)
{
scanf("%d",&t);
update(i,t,1);
}
for(i = 1; i <= m; i++)
{
getchar();
//这里用fflush(stdin);不对啊
scanf("%c",&ch);
//这里加个fflush(stdin);,就死机啊啊啊 ????这地方的问题交给你。
scanf("%d %d",&a,&b);
if(ch == 'Q')
printf("%d\n",query(a,b+1,1));//注意是b+1而不是b。因为线段树是一个左开右闭的的区间。
else
update(a,b,1);
}
}
return 0;
}
看着很像吧,基本模板是这样。先会基本思想和套路,变化和应用要考多做题!!!