摘要: 这是一道树状数组的应用题,题意是要对一个序列按升序排序,每次交换相邻两个数,求交换次数。假设a,b,c相邻,如果a>b,a>c,那么a,b就应该先交换一次,a和c再交换一次。所以这道题就抽象为求逆序数,即对每个i,找到a[i]的左边比a[i]大的数的个数,求出总和。由于树状数组可以很方便地求出一个数左边比它小的数的个数,所以进一步转化为:对每个i,找到从a[i]开始,到最左边小于等于a[i]的数的个数,然后用i减去这个数,就得到a[i]左边比a[i]大的数的个数。 具体来说,就是维护一个数组(c[]),初始化所有值为0,对需要统计逆序数的序列,从左向右依次加入序列中的点,比如序列a 阅读全文
posted @ 2012-08-08 16:00 等待电子的砹 阅读(115) 评论(0) 推荐(0) 编辑
摘要: 一道线段树的区间修改题,给区间染色,最后输出一个区间的颜色种数,由于颜色不会超过30种,所以可以用int型二进制的每一位表示一种颜色,比如颜色1就是000……0001,颜色3是000……100,那么一个区间内如果有两种颜色A和B,管辖这两个区间的大区间的颜色就为 A|B,最后根据查询到的数得出二进制中1的个数,从而判断出有几种颜色。 写这道题的时候,swap函数出现了一个错误: swap(int *a,int *b) int *c if(*a>*b) *c=*a; *a=*b; *b=*a; 这暴露出我的C语言基础还不扎实,开始声明*c的时候没有赋值,后来又要对... 阅读全文
posted @ 2012-08-08 09:08 等待电子的砹 阅读(223) 评论(0) 推荐(0) 编辑
摘要: 一道线段树的区间修改题,和POJ3468非常类似,都是利用lazy-tag来加快速度,lazy-tag在poj 3468的解题报告中有说明。不同之处在于这里是更改stick的类型,所以对tag直接赋值就行了。另外,初始的stick为1,所以在建树的时候需要注意。#include<stdio.h>#include<string.h>#define MAX_HOOK 100005struct node{ int left; int right; int sum; int tag;}stick[4*MAX_HOOK];void build(int,int,int);voi.. 阅读全文
posted @ 2012-08-07 19:03 等待电子的砹 阅读(226) 评论(0) 推荐(0) 编辑
摘要: 一道线段树的区间修改题,以前写的线段树都是单点修改,这里用到了区间修改。我开始觉得单点修改和区间修改差不多,把区间内每个点进行一次单点修改就是区间修改了,这样虽是可行,但是时间复杂度却大大增加,想想看,一个点一个点地修改,这和暴力有什么区别呢。 在网上找了好多资料,终于弄明白了用lazy-tag(lazy标记)进行区间修改。我的理解是这样的,为了减小修改次数,先将要进行的修改存起来,当访问到子节点的时候,如果发现父节点带有标记,就顺便将子节点更新,就像搭顺风车一样。在这道题中,每次可能要对一个区间加上一个值,比如全集为[1,7],现在要对区间[1,4]进行操作,例如要将[1,4]每个值都... 阅读全文
posted @ 2012-08-07 17:03 等待电子的砹 阅读(132) 评论(0) 推荐(0) 编辑
摘要: 这同样是一道线段树的入门题,与HDU 1166非常类似,都是了解其基本的操作。不同是这一道是求最大值,所以query的操作略有不同。值得注意的是,节点数应该为题目所给的MAXN*4(HDU 1166也是)。这一点我还没明白是为什么。 #include<stdio.h>#include<string.h>#include<stdlib.h>#define MAX_STUDENTS 200002#define INF 1000000struct node{ int left; int right; int max;}studnt[MAX_STUDENTS*4]; 阅读全文
posted @ 2012-08-06 11:33 等待电子的砹 阅读(336) 评论(0) 推荐(0) 编辑
摘要: 这是一道线段树的入门题,用于学习基本的线段树的建树、更新、访问的操作。只在这里说说基本的操作。 首先是建树(void build(int root,int le,int ri)),采用递归的方式:root为当前节点,le为区间的左端点,ri为区间的右端点;如果le==ri,说明此时长度为1,建到最底层了,所以返回;否则,建立左子树和右子树,显然左子树在数组中的下标为2*root,右子树为2*root+1,这时还要将区间一分为二,左子树负责[le,(le+ri)/2]的部分,右子树负责[(le+ri)/2+1,ri]的部分。另外一个操作是更新(void fix(int root,int l... 阅读全文
posted @ 2012-08-06 10:36 等待电子的砹 阅读(162) 评论(0) 推荐(0) 编辑
摘要: 并查集应用,只要会做POJ2492,这道题也没什么问题了,也是利用偏移量解题,注意的是,为了方便起见,relation[x]=0表示x与x的根节点的关系是同类,relation[x]=1表示x被x的根节点吃,relation[x]=2表示x吃x的根节点。所以读入kind的时候应该改一下。另外,x吃x才算错,所以数据如1 5 5是正确的。有关偏移量,在POJ 2492的解题报告中有详细的说明,由于这道题POJ只有单组数据,所以while scanf()!=EOF应该去掉。#include<stdio.h>#define MAX_ANIMAL 50010int get_root(int 阅读全文
posted @ 2012-08-04 16:47 等待电子的砹 阅读(225) 评论(0) 推荐(0) 编辑
摘要: 这是一道并查集应用的基础题,关键是靠这道题理解偏移量,gender[x]表示x节点与根节点的关系,0表示同属性,1表示不同属性,每次得到一组数据,首先判断它们的根节点是否相同,如果不同,则合并,如果相同,则判断它们与根节点的关系,如果它们与根点的关系相同,那么它们之间的关系也相同,则找到了suspicous bug. 解题的关键就在于对偏移量的理解,首先考虑合并集合,即函数unon().x的根节点为a,y的根节点为b,要合并这两个集合,就应该更新a与b的关系,由于已知了x与y的关系(题目每给出一对虫子,如果它们不属于一个集合,则说明它们关系为1,现在应该合并它们所在的集合),所以能得出g... 阅读全文
posted @ 2012-08-04 11:37 等待电子的砹 阅读(203) 评论(0) 推荐(0) 编辑
摘要: 这是又是一道01背包的变体,题目要求选出一些牛,使smartness和funness值的和最大,而这些牛有些smartness或funness的值是负的,还要求最终的smartness之和以及funness之和不能为负。 这道题的关键有两点:一是将smartness看作花费、将funness看作价值,从而转化为01背包;二是对负值的处理,引入一个DELTA来表示“0”,这里的DELTA一定要大于每一个smartness的绝对值,另外在遍历cost[]的时候如果cost[i]>0,显然时从开的数组的最大值MAX_LMT开始往下减,如果cost[i]<0,则是从0(是0,不是DELTA 阅读全文
posted @ 2012-08-01 22:31 等待电子的砹 阅读(592) 评论(0) 推荐(1) 编辑
摘要: 这是一道可以用多重背包来写的题,但是这种方法速度很慢,2829MS。思路很简单,将多重背包转化为01背包,dp所对应的下标为钱数,如果能刚好凑到下标所对应的钱数,就赋为1。最后输出被赋为1的个数就是可能性。#include<stdio.h>#include<string.h>#define MAX_PRICE 1000000#define MAX_COIN 110void mk_list(int,int,int);int top=1,stk[MAX_PRICE];int main(){ int n,m; while(scanf("%d%d",& 阅读全文
posted @ 2012-07-30 23:50 等待电子的砹 阅读(239) 评论(0) 推荐(0) 编辑