数据结构报告

报告用的,和之前的内容可能有点重请见谅;)

线段树降维

恍然大悟

给出一些矩形的位置和大小,求总共覆盖面积。
示意图

解法:
一个方向作为扫描线。另一个方向坐标离散化。
扫描线往上划,依次更新区间。

注意:定义好每个变量的含义。
cover是一个区间被完全覆盖时,计数覆盖了几重。子区间不用继承父区间的重数,否则在更新时会出错!(这点坑了一天)
has是一个区间完全没被覆盖置为0,否则只要沾边就置为1.当子区间has为1时,父区间has必定为1.同时该区间cover>0时,has必为1.

void update(int rt, int beg, int end, int l, int r, int flag)
{
    if(l > r || end < l || r < beg) return;
    if(l <= beg && end <= r)
    {
        cover[rt] += flag;
        if(beg == end)
            has[rt] = cover[rt] ? 1 : 0;
        else
            has[rt] = cover[rt]||has[rt<<1]||has[rt<<1|1] ? 1 : 0;
        return;
    }
    int mid = beg + end >> 1;
    update(rt<<1, beg, mid, l, min(r, mid), flag);
    update(rt<<1|1, mid+1, end, max(mid+1, l), r, flag);
    has[rt] = cover[rt]||has[rt<<1]||has[rt<<1|1] ? 1 : 0;
}
double query(int rt, int l, int r)
{
    if(!has[rt])
        return 0;
    if(cover[rt])
        return a[r+1]-a[l];
    int mid = l+r >> 1;
    return query(rt<<1, l, mid) + 
    query(rt<<1|1, mid+1, r);
}

另一道类似的题

给出一些矩形的位置和大小,求覆盖的周长。

并查集

不要再继续用rank做题了!
类似于向量,每次记录相对值。

int get(int a){
    if(p[a] != a) p[a] = get(p[a]);
    return p[a];
}

经过get操作后,a点直接指向所在团的团长,把路径上的箭头压缩了。

堆积的雏形

初始为n个方块。有以下两种操作:
1. 将x及以下的方块放到y所在的堆上;
2. 询问x所在的堆上一共有多少个方块。

解法:
合理构造有助于求解。每次移动以后,让最底下的积木作为团长。
p[i]: i所在堆的团长,初始为i
a[i]: i底下有多少个积木,初始为0
s[i]: i为团长时,表示这堆积木的总数,初始为1
每次get时,也要更新a的值,让a[i]为i的熟人到新团长的链上的a[j]之和,不含新团长。
“该链上只有i,老团长,新团长,所以j就是老团长这一个”,对吗?

int get(int x){
    if(p[x] != x){
        a[x] += a[p[x]];
        p[x] = get(p[x]);
    }
    return p[x];
}

事实上,多次merge可能会造成长链,上面的写法是错滴!比较好的递归写法如下:

int get(int x){
    if(p[x] != x){
        int t = get(p[x]);
        a[x] += a[p[x]];
        p[x] = t;
    }
    return p[x];
}

就差一丢丢,先后次序决定了p[x]已经被先行处理,a[p[x]]值发生了改变。写不出来的话,还有再傻一点的写法如下:

int get(int x){
    if(p[x] != x){
        int t = get(p[x]), y = x;
        while(p[y] != t){
            a[x] += a[p[y]];
            y = p[y];
        }
        p[x] = t;
    }
    return p[x];
}

乍一看不像并查集

有n个物品即将过期,给出了原价和过期时间,过期则价值为0。求最佳的出售安排,使得物品价值和最大。

解法:
第一关键字:价值 第二关键字:日期 排序
每次排入的物品想要放入的位置若已经被安排,则只能放在该线段的最左端。

我没有说谎

n个人说了n句话,可能为真也可能为假。当它们相互矛盾时,输出Inconsistent。否则就输出最多有几个人说了真话。

解法:
x说“y说了真话”,则x和y同真假;否则x和y不同真假。
“x说了真话”和“x说了假话”这两种情况相互对称,因此只要给出所有人相对x的真假性即可。

组队方案

只有相互认识的人才可以组队。将所有人分成两队,人数分别为x和y。求使得x和y差值最小的组队方案。

解法:
相互不认识的人可以建立关系。建立多个团。要DP啊!

可持久化

在移动木块中还有操作3:将x从一堆中删除。

解法:
重新建立编号,伪持久化。

恢复到第k个操作时的情况?

你可能感兴趣的:(数据结构)