• HODJ1166敌兵布阵树状数组和线段树求解


    题目:http://acm.hdu.edu.cn/showproblem.php?pid=1166

    基维百科:http://zh.wikipedia.org/wiki/%E6%A0%91%E7%8A%B6%E6%95%B0%E7%BB%84

    http://duanple.blog.163.com/blog/static/7097176720081131113145832/

    树状数组源码及部分注释:

    #include<stdio.h>
    #include<string.h>
    #define MAX 50010
    int N;
    int per[MAX],C[MAX];
    
    int lowbit(int n)
    {//此函数实际就是将n的二进制表示形式留下最右边的1,其他位都变为0
    	return n&(-n);
    }
    void update(int i,int x)//更新值
    {
    	while(i <= N)
    	{
    		C[i] += x;
    		i += lowbit(i);
    	}
    }
    int check(int n)//求从第一个数到第n个数的和
    {
    	int sum = 0;
    	while( n > 0)
    	{
    		sum += C[n];
    		n -= lowbit(n);
    	}
    	return sum;
    }
    int main()
    {
    	int i,T,k,j,num = 1,a,b;
    	char str[10];
    	scanf("%d",&T);
    	while( T-- )
    	{
    		scanf("%d",&N);
    		//初始化数组C
    		memset(C,0,sizeof(C));
    		//输入原始数据
    		for(i = 1; i <= N; i++)
    			scanf("%d",&per[i]);
    
    		//构造树状数组
    		for(i = 1; i <= N; i++)
    		{
    			j = lowbit(i);
    			for(k = i - j + 1; k <= i; k++)
    				C[i] += per[k];
    		}
    		printf("Case %d:\n",num++);
    		while(scanf("%s",str) && str[0] != 'E')
    		{
    			scanf("%d%d",&a,&b);
    			switch( str[0] )
    			{
    			case 'Q':
    				printf("%d\n",check(b) - check(a-1));
    				break;
    			case 'S':
    				update(a,-b);
    				break;
    			case 'A':
    				update(a,b);
    				break;
    			}
    		}
    	}
    	return 0;
    }

    线段树Segment Tree)是一种二叉搜索树,它将一个区间划分成一些单元区间,每个单元区间对应线段树中的一个叶结点

    对于线段树中的每一个非叶子节点[a,b],它的左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2+1,b]。因此线段树是平衡二叉树。叶节点数目为N,即整个线段区间的长度。

    使用线段树可以快速的查找某一个节点在若干条线段中出现的次数,时间复杂度为O(logN)。而未优化的空间复杂度为2N,因此有时需要离散化让空间压缩。


    线段树求解源代码及部分注释:

     
    #include<stdio.h>
    #include<stdlib.h>
    #include<string.h>
    #define maxn 50010
    struct node 
    {
    	int left,right;
    	int count;
    }st[maxn * 6];
    void build(int curnode,int left,int right)//创建线段树,
    {
    	st[curnode].left = left;
    	st[curnode].right = right;
    	st[curnode].count = 0;
    	if(left == right)//当到达叶子节点的时候则返回
    		return ;
    	//将子树继续二分,
    	build(curnode*2,left,(left+right)/2);
    	build(curnode*2+1,(left+right)/2+1,right);
    }
    void update(int curnode,int seq,int cnt)
    {//更新线段树
    	if(seq <= st[curnode].right && seq >= st[curnode].left)
    	{
    		st[curnode].count += cnt;
    		update(curnode*2,seq,cnt);
    		update(curnode*2+1,seq,cnt);
    	}
    }
    int total;
    void sum(int curnode,int left,int right)
    {//求和
    	int mid = (st[curnode].left + st[curnode].right)/2;
    	if(st[curnode].left == left && st[curnode].right == right)
    		total += st[curnode].count;
    	else
    		if(right <= mid )
    			sum(curnode * 2,left,right);
    		else
    			if(left > mid)
    				sum(curnode*2+1,left,right);
    			else
    			{
    				sum(curnode*2,left,mid);
    				sum(curnode*2+1,mid+1,right);
    			}
    }
    int main()
    {
    	int T,num,pernum,i;
    	char ins[10];
    	int a,b,c = 1,flg;
    	scanf("%d",&T);
    	while( T--)
    	{
    		scanf("%d",&num);
    		memset(st,0,sizeof(st));
    		build(1,1,num);
    		for( i = 1; i <= num; i++)
    		{
    			scanf("%d",&pernum);
    			update(1,i,pernum);
    		}
    	 printf("Case %d:\n", c++);
    	 flg = 1;
    		while( scanf("%s",ins) != EOF && ins[0] != 'E')
    		{
    			
    			scanf("%d%d",&a,&b);
    			switch(ins[0])
    			{
    			case 'Q':
    				total = 0;
    				sum(1,a,b);
    				printf("%d\n",total);
    				break;
    			case 'A':
    				update(1,a,b);
    				break;
    			case 'S':
    				update(1,a,-b);
    				break;
    				
    			}
    		}
    	}
    	return 0;
    
    }
  • 相关阅读:
    SVN 常用keywords 记录
    HTML5新特性介绍
    php文件上传错误代码
    MySQL的 Grant命令权限分配
    前端开发工具整理
    Java多线程编程经验谈
    一套密码强度判断方案
    傲游浏览器下Flash和Js交互问题
    在xml中使用&和字符
    ibatis和myibatis
  • 原文地址:https://www.cnblogs.com/LUO257316/p/3220848.html
Copyright © 2020-2023  润新知