HDU 1166 敌兵布阵(线段树或数状数组)

题目地址:点击打开链接

思路:不要用cin,cout,输入输出,会超时,update(),单点增减,query()区间求和,前2个代码是为了便于理解,写的时候看第三个代码,特别简洁

AC代码:

#include <iostream>
#include <cstdio>

using namespace std;

int n,sum;
int a[50010];

struct node
{
    int l;
    int r;
    int value;
}tree[500000];//开数据量的4倍左右

void bulid(int v,int l,int r)
{
    tree[v].l = l;
    tree[v].r = r;
    if(l == r)
    {
        tree[v].value = a[l];
        return;
    }
    int mid = (l + r) / 2;
    bulid(v*2,l,mid);
    bulid(v*2+1,mid+1,r);
    tree[v].value = tree[v*2].value + tree[v*2+1].value;
}

void update(int v,int l,int r,int m)
{
    if(tree[v].l == l && tree[v].r == r)
    {
        tree[v].value += m;
        return;
    }
    int mid = (tree[v].l + tree[v].r) / 2;
    if(r <= mid)//到目前节点的左节点去找要找的区间
        update(v*2,l,r,m);
    else
        update(v*2+1,l,r,m);//到目前节点的右节点去找要找的区间
    tree[v].value = tree[v*2].value + tree[v*2+1].value;//往上传增量
}

void query(int v,int l,int r)
{
    if(tree[v].l == l && tree[v].r == r)
    {
        sum += tree[v].value;
        return;
    }
    int mid = (tree[v].l + tree[v].r) / 2;
    if(r <= mid)
        query(v*2,l,r);//只跨一个区间,到目前节点的左节点去查询
    else if(l > mid)
        query(v*2+1,l,r);//只跨一个区间,到目前节点的右节点去查询
    else//横跨二个区间,左右节点都得查询
    {
        query(v*2,l,mid);
        query(v*2+1,mid+1,r);
    }
}

int main()
{
    char s[10];
    int t,x,y,i,l = 1;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(i=1; i<=n; i++)
        {
            cin>>a[i];
        }//在update()函数输入也可,不用设a这个数组
        bulid(1,1,n);
        printf("Case %d:\n",l++);
        while(scanf("%s",s) && s[0] != 'E')
        {
            scanf("%d%d",&x,&y);
            if(s[0] == 'Q')
            {
                sum = 0;
                query(1,x,y);//第一个参数是节点,第二个参数是左端点,第三个参数是右端点
                printf("%d\n",sum);
            }
            else if(s[0] == 'A')
                update(1,x,x,y);//第一个参数是节点,第二个参数是左端点,第三个参数是右端点,第四个参数是增量
            else if(s[0] == 'S')
                update(1,x,x,-y);
        }
    }
    return 0;
}

AC代码2:(用了位运算,应该快一点)

#include <iostream>
#include <cstdio>

using namespace std;

int n,sum;
int a[50010];

struct node
{
    int l;
    int r;
    int value;
}tree[500000];//开数据量的4倍左右

void bulid(int v,int l,int r)
{
    tree[v].l = l;
    tree[v].r = r;
    if(l == r)
    {
        tree[v].value = a[l];
        return;
    }
    int mid = (l + r) >> 1;
    bulid(v<<1,l,mid);
    bulid(v<<1|1,mid+1,r);
    tree[v].value = tree[v<<1].value + tree[v<<1|1].value;
}

void update(int v,int l,int r,int m)
{
    if(tree[v].l == l && tree[v].r == r)
    {
        tree[v].value += m;
        return;
    }
    int mid = (tree[v].l + tree[v].r) >> 1;
    if(r <= mid)//到目前节点的左节点去找要找的区间
        update(v<<1,l,r,m);
    else
        update(v<<1|1,l,r,m);//到目前节点的右节点去找要找的区间
    tree[v].value = tree[v<<1].value + tree[v<<1|1].value;//往上传增量
}

void query(int v,int l,int r)
{
    if(tree[v].l == l && tree[v].r == r)
    {
        sum += tree[v].value;
        return;
    }
    int mid = (tree[v].l + tree[v].r) >> 1;
    if(r <= mid)
        query(v<<1,l,r);//只跨一个区间,到目前节点的左节点去查询
    else if(l > mid)
        query(v<<1|1,l,r);//只跨一个区间,到目前节点的右节点去查询
    else//横跨二个区间,左右节点都得查询
    {
        query(v<<1,l,mid);
        query(v<<1|1,mid+1,r);
    }
}

int main()
{
    char s[10];
    int t,x,y,i,l = 1;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(i=1; i<=n; i++)
        {
            cin>>a[i];
        }//在update()函数输入也可,不用设a这个数组
        bulid(1,1,n);
        printf("Case %d:\n",l++);
        while(scanf("%s",s) && s[0] != 'E')
        {
            scanf("%d%d",&x,&y);
            if(s[0] == 'Q')
            {
                sum = 0;
                query(1,x,y);//第一个参数是节点,第二个参数是左端点,第三个参数是右端点
                printf("%d\n",sum);
            }
            else if(s[0] == 'A')
                update(1,x,x,y);//第一个参数是节点,第二个参数是左端点,第三个参数是右端点,第四个参数是增量
            else if(s[0] == 'S')
                update(1,x,x,-y);
        }
    }
    return 0;
}

AC代码3:(上面代码风格太丑了,参考大神的代码写的)

大神地址:http://blog.csdn.net/metalseed/article/details/8039326

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <cstring>
#include <climits>
#include <cmath>
#include <cctype>
const int inf = 0x3f3f3f3f;//1061109567
typedef long long LL;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn = 50010;
using namespace std;
int sum[maxn<<2];
char a[10];
void pushup(int rt)
{
    sum[rt] = sum[rt<<1]+sum[rt<<1|1];
}
void build(int l,int r,int rt)
{
    if(l == r)
    {
        scanf("%d",&sum[rt]);
        return;
    }
    int m = (l+r)>>1;
    build(lson);
    build(rson);
    pushup(rt);
}
void update(int c,int op,int l,int r,int rt)
{
    if(l == r)
    {
        sum[rt] += op;
        return;
    }
    int m = (l+r)>>1;
    if(c <= m) update(c,op,lson);
    else update(c,op,rson);
    pushup(rt);
}
int query(int L,int R,int l,int r,int rt)
{
    if(l>=L && r<=R) return sum[rt];
    int m = (l+r)>>1;
    int ans = 0;
    if(L <= m) ans += query(L,R,lson);
    if(R > m) ans += query(L,R,rson);
    return ans;
}
int main()
{
    int t,n,cas=1;
    scanf("%d",&t);
    while(t--)
    {
        int c,d;
        printf("Case %d:\n",cas++);
        scanf("%d",&n);
        build(1,n,1);
        while(scanf("%s",a) && a[0] != 'E')
        {
            scanf("%d%d",&c,&d);
            if(a[0] == 'Q') printf("%d\n",query(c,d,1,n,1));
            else if(a[0] == 'A') update(c,d,1,n,1);
            else if(a[0] == 'S') update(c,-d,1,n,1);
        }
    }
    return 0;
}

AC代码4:

#include<stdio.h>
#include<string.h>
int a[50010];
char sh[15];
int n;
int lowbit(int x)
{
	return x&(-x);
}
void update(int pos,int num)
{
	while(pos<=n)
	{
		a[pos] += num;
		pos += lowbit(pos);//把他的父节点也改了
	}
}
int sum(int end)//求1到end的值
{
	int sum = 0;
	while(end>0)
	{
		sum += a[end];
		end -= lowbit(end);//1-end由多段值组成,分别求多段的值
	}
	return sum;
}
int main()
{
	int t,i,x,y,l = 1,sum1;
	scanf("%d",&t);
	while(t--)
	{
		memset(a,0,sizeof(a));
		scanf("%d",&n);
		for(i=1; i<=n; i++)
		{
			scanf("%d",&x);
			update(i,x);
		}		
		printf("Case %d:\n",l++);
		while(scanf("%s",sh))
		{
			if(sh[0] == 'Q')
			{		
				scanf("%d%d",&x,&y);
				sum1 = sum(y) - sum(x-1);
				printf("%d\n",sum1);
			}
			else if(sh[0] =='A')
			{	
				scanf("%d%d",&x,&y);
				update(x,y);
			}
			else if(sh[0] == 'S')
			{
				scanf("%d%d",&x,&y);
				update(x,-y);
			}
			else if(sh[0] == 'E')
				break;
		}
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值