题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1166
原来的我的代码,空指针异常,
import java.util.Scanner;
class test6{
static int T;
static int N;
static int x = 1;
static int a[] = new int[50001];
static Node b[] = new Node[150005]; //要开三倍空间
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
T = sc.nextInt();
while (T-->0){
N = sc.nextInt();
for(int i = 1;i<=N;i++){
a[i]= sc.nextInt();
}
System.out.println("Case "+(x++));
Build(1,N,1);
while (true){
String s = sc.next();
if(s.equals("End")) break;
if(s.equals("Query")){
int c = sc.nextInt();
int d = sc.nextInt();
int ans = query(c,d,1);
System.out.println(ans);
}
if(s.equals("Add")){
int c = sc.nextInt();
int num = sc.nextInt();
add(c,num,1);
}
if(s.equals("Sub")){
int c = sc.nextInt();
int num = sc.nextInt();
add(c,-num,1);
}
}
}
}
static int query(int left,int right,int i){
if(b[i].left==right && b[i].right ==right) return b[i].sum;
int mid = (b[i].left +b[i].right )/2;
if(right<=mid ) return query(left ,right,2*i);
else if(right>mid) return query(left,right,2*i+1);
else return query(left ,mid,2*i)+query(mid+1,right,2*i+1);
}
static void add(int j,int num,int i){
if(b[i].left==b[i].right){
b[i].sum+= num;
return;
}else {
b[i].sum += num;
if(j<=b[i*2].right) add(j,num,2*i);
else add(j,num,2*i+1);
}
}
public static void Build (int left, int right, int i){
b[i].left = left;
b[i].right = right;
if(left==right){
b[i].sum = a[left];
return;
}
int mid = (left+right)/2;
Build(left,mid,2*i);
Build(mid+1,right,2*i+1);
b[i].sum = b[2*i].sum + b[2*i+1].sum;
}
class Node{
int left;
int right;
int sum;
}
}
ac代码:(c++)
/**
*线段树的简单应用,用scanf和printf输入输出
*cin和cout会超时
*/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
int a[50001];//存储结点的位置
struct node{
int left,right;//线段区间
int sum;//区间上的人数
}b[150005];
void Build(int left,int right,int i){//建树
int mid;
b[i].left=left;
b[i].right=right;
if(left==right){//先用数组存下该队的人
b[i].sum=a[left];
return ;
}
//cout<<"ok"<<endl;
mid=(left+right)/2;
Build(left,mid,2*i);//递归建立左子树
Build(mid+1,right,2*i+1);//递归建立右子树
b[i].sum=b[2*i].sum+b[2*i+1].sum;//记录该结点左右子树的值
}
void Add(int j,int num,int i){
if(b[i].left==b[i].right){//到达叶子结点
b[i].sum+=num;
return ;//注意返回
}
else{
b[i].sum+=num;//他的所有父节点都增加
if(j<=b[i*2].right) Add(j,num,2*i);//递归左子树
else Add(j,num,2*i+1);//建立右子树
}
}
int Query(int left,int right,int i){//查询
int mid;
if(b[i].left==left&&b[i].right==right) return b[i].sum;
mid=(b[i].left+b[i].right)/2;
if(right<=mid) return Query(left,right,2*i);//在左子树
else if(left>mid) return Query(left,right,2*i+1);//在右子树
else return Query(left,mid,2*i)+Query(mid+1,right,2*i+1);//否则在中间
}
int main()
{
int t,k=0,i,j,num,n;
char s[10];
scanf("%d",&t);
while(t--){
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%d",&a[i]);
}
//cout<<"Case "<<++k<<":"<<endl;
printf("Case %d:\n",++k);
Build(1,n,1);//建树
while(1){
scanf("%s",s);
if(!strcmp(s,"End")) break;
scanf("%d%d",&j,&num);
if(!strcmp(s,"Query")){
printf("%d\n",Query(j,num,1));
//cout<<Query(j,num,1)<<endl;
}
if(!strcmp(s,"Add")) Add(j,num,1);//从根结点开始
if(!strcmp(s,"Sub")) Add(j,-num,1);
}
}
return 0;
}
再来一题:
http://acm.hdu.edu.cn/showproblem.php?pid=1754
非递归线段树
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll maxn=200005;
ll Max[maxn*4];
ll a[maxn];
ll N,m,n;
void btree(int x)
{
N=1;
while(N<x+2)
N*=2;
for(int i=1;i<=x;i++)
Max[N+i]=a[i];
for(int i=N-1;i>0;i--)
{
Max[i]=max(Max[i*2],Max[i*2+1]);
}
}
ll query(int l,int r)
{
ll ans=0;
for(int s=N+l-1,t=N+r+1;s^t^1;s/=2,t/=2)
{
if(~s&1) ans=max(ans,Max[s^1]);
if(t&1) ans=max(ans,Max[t^1]);
}
return ans;
}
void update(int l,int c)
{
for(int s=N+l;s;s/=2)
Max[s]=c;
}
int main()
{
while(scanf("%lld %lld",&n,&m)!=EOF){
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
getchar();
btree(n);
char op[2];
ll num1,num2;
for(int kk=0;kk<m;kk++)
{
scanf("%s %lld %lld",op,&num1,&num2);//坑点必须为%s,%c就wa
if(op[0]=='Q'){
printf("%lld\n",query(num1,num2));
}
else if(op[0]=='U')
update(num1,num2);
}
}
return 0;
}