today,我深刻得体会到了“暴力出奇迹”的真谛。首先,今天我很开心(假的),早上听老师在讲台上讲了一早上,看起来什么都懂了,但是,一到考试照样暴力,奇迹般,这次居然暴力到了70分,不错不错。今天上课内容如下:
NO.1并查集
并查集,其实就是用于“合并集合”和“查找集合”的算法。
具体的:
“集”就是这个算法是用来处理集合问题的;
“并”就是可以按需要将属于同一组的元素所在的集合合并;
“查”就是查询元素所在集合,查询不同元素、不同集合之间的关系。
看样子学完了,其实,不是这样的。。。。重点在下面(操作如下):
(我们定义一个father数组,记录树形结构中节点的父亲,那么father[x]=x)
初始化操作:(将每个元素的父亲设置成自身)
for(int i=1;i<=n;i++)
father[i]=i;
判断数据所属的集合:(不断查找当前节点的祖先,直至找到father[x]=x,x就是代表元)
int findFather(int x)
{
if(father[x]=x)
return x;
else
return findFather(father[x]);
}
但是这样浪费太大,我们可以将路径压缩:
Int findFather(int x)
If(father[x]==x) return x;
Else
{
Father[x]=findFather[x];
Return father[x];
}
集合合并:(把其中任意一个集合的代表元的父亲修改为另一个集合的代表元)
int fu , fv;
fu = findFather(u);
fv = findFather(v);
father[fu] = fv;
eg:关押罪犯
题目大意:略
分析:其中用到了一些贪心思想,先把怨气值从大到小排序,依照贪心策略尽量将怨气值大的两个罪犯关押到不同的监狱,每次关押前检测两罪犯是否已经被关到一起,若被关到一起则无法再次分配,怨气值即题所求。(代码不符)
树状数组
一种支持数据修改的快速求前缀和算法,也是一种只记录部分在二进制上具有关联的数据的前缀和算法,是支持动态修改的求解前缀和方法。
计算移动距离:(计算机补码的特点,可以很简便的通过 x & (-x) 来求得x的二进制表示,仅保留最低位1得到的数字,也就是这个跳跃间隔。(不理解也没关系))
int lowbit(x){
return (x & (-x));}
求前缀和:(每次往前跳跃lowbit(x),直到最前)
int getsum(int k){
int sum = 0;
while(k > 0){
sum += star[k];
k -= lowbit(k);
}return sum;
}
动态修改(只需要把增量同步到所有记录了这个数据的位置上即可)
void modify(int x , int delta){
while(x <= N){
star[x] += delta;
x += lowbit(x);
}
}
初始化
for(int i = 1 ; i <= N ; ++i){
modify(i , d[i]);}
eg:逆序对
题目大意:略
分析:假设我们已经知道数列{ a[1], a[2], …, a[k - 1] }的逆序对数目。当a[k]加入,会产生的逆序对数取决于{ a[1], a[2], …, a[k - 1]}中有多少个数字大于a[k]。所以我们可以开一个数组来记录数字a[i]出现的次数。那么对出现次数做前缀和。若t是前缀和,t[a[k]]就记录着有多少个数字小等于a[k]。t[MAXA] - t[a[k]]就记录着有多少个数字大于a[k]。每次询问(a[k] – 1)的前缀和是多少,并把a[k]位置+1。