• 数据结构


    数据结构

    线段树可以维护的:

    • 区间最值
    • 区间和
    • 区间最大差值
    • 区间颜色段数

    BZOJ1227: [SDOI2009]虔诚的墓主人

    题意:

    坐标上种有一些树
    定义一个点的十字架数量为, 正的上下左右方向各选(k(le 10))棵树的方案数
    然后种有树的坐标上数量为(0)
    求整张图上有多少十字架

    Sol:

    按行枚举
    用数据结构维护X坐标区间上下选的方案数
    对于每一行枚举所有点, 根据上述方案数 * 左右选的方案数累加答案

    讨论一下推移到下一行, 这个X坐标上有树没树的变化, 并记录这个X坐标上, 大于/小于Y的有几个, 就可以更新上下选的方案数了

    LL Comb(LL n)
    {
        if (m > n) return 0;
        return C[n][m];
    }
    
    namespace BIT
    {
        LL val[MAXN];
        int lowbit(int x) { return x & (-x); }
        void add(int x, int v)
        {
    	for (; x <= n; x += lowbit(x)) (val[x] += v) %= MOD;
        }
        LL query(int x)
        {
    	LL ret = 0;
    	for (; x >= 1; x -= lowbit(x)) (ret += val[x]) %= MOD;
    	return ret;
        }
    }
    
    int upp[MAXN], low[MAXN], last[MAXN];
    
    void solve(int Y, int l, int r)
    {
        for (int i = l; i <= r; ++ i)
        {
    	int X = a[i].x;
    	LL now = Comb(upp[X] - 1) * Comb(low[X]) % MOD;
    	LL pre = Comb(upp[X]) * Comb(low[X]) % MOD;
    	-- upp[X];  
    	BIT :: add(X, (now - pre + MOD) % MOD);
    	last[X] = Y;
        }
        for (int i = l + 1; i <= r; ++ i)
        {
    	(ans += (BIT :: query(a[i].x - 1) - BIT :: query(a[i - 1].x) + MOD) % MOD * Comb(i - l) % MOD * Comb(r - i + 1) % MOD) %= MOD;
        }
        for (int i = l; i <= r; ++ i)
        {
    	int X = a[i].x;
    	LL now = Comb(upp[X]) * Comb(low[X] + 1) % MOD;
    	LL pre = Comb(upp[X]) * Comb(low[X]) % MOD;
    	low[X] ++;
    	BIT :: add(X, (now - pre + MOD) % MOD);
    	last[X] = Y;
        }
    }
    
    int main()
    {
        n = in(); n = in();
        n = in();
        for (int i = 1; i <= n; ++ i)
    	a[i] = (Poi) { in(), in() };
        m = in();
        init();
        sort(a + 1, a + n + 1, cmp);
        for (int i = 1; i <= n; ++ i)
    	if (a[i].y > 0) ++ upp[a[i].x];
        for (int Y = 1, i = 1; Y <= n && i <= n; ++ Y)
        {
    	while (a[i].y < Y && i <= n) ++ i;
    	if (a[i].y != Y) continue;
    	int l = i, r = i;
    	while (a[i + 1].y == Y && i + 1 <= n) ++ i;
    	r = i;
    	solve(Y, l, r);
    	++ i;
        }
        printf("%lld
    ", ans);
        return 0;
    }
    

    BZOJ3531: [Sdoi2014]旅行

    题意:

    (N)个城市的树, 每个城市有一个信仰(C[i])和点权(W[i]), 如果一个人走一条起终点信仰相同的简单路径, 他会记录路径上和起终点信仰相同的城市的权值

    有以下操作: 改某个城市的信仰/权值, 求一条路径记录的点权的最大值/和

    Sol:

    先树链剖分, 得到一个序列, 然后为每一种信仰动态开点建一棵位置线段树, 修改就加减一下, 查询就跳重链查

    动态开点空间是(nlogn)的, 每次查询(log^2n)

    BZOJ3932: [CQOI2015]任务查询系统

    题意:

    (N)个任务, 每个任务有开始/结束时间,和权值
    同一时间可能会有多个任务同时进行, 也可能有多个任务权值相同

    强制在线查询某个时间点, 按权值从小到大的前(k)个权值的和(每次(k)不同)

    Sol:

    差分, 将任务拆成两个点, 然后按时间排序, 依次插入主席树

    一个时间点可能插多次, 第一次以上一个时间为模板插入这个点, 之后的以自己为模板一样操作即可

    查询不用多说了, 像二叉查找树一样搜下去即可

    BZOJ1926: [Sdoi2010]粟粟的书架

    给出一个矩阵, 上面有数, 每次查询求至少选多少个加起来能超过或等于某数

    数据范围很微妙:

    • 对于50%的数据,满足(R, C≤200,M≤200,000)
    • 另有50%的数据,满足(R=1,C≤500,000,M≤20,000)
    • 对于100%的数据,满足(1≤Pi,j≤1,000,1≤Hi≤2,000,000,000)

    Sol:

    我以为两种都是主席树做的, 然后我寻思不管怎么预处理每个点都会含有(n^2)级别的数
    意味着每个坐标暴力插(n^2)次, 还是继承上一行插(n)次都不会T, 但是无论如何都会MLE

    其实(200*200)不用数据结构直接暴力即可...
    剩下一条链就不用说了

    BZOJ2243: [SDOI2011]染色

    注意到一个问题:
    线段树的查询函数中要不要pushup() ?

    每次pushdown()操作时, 会更新这个点的信息为正确值, 如果不pushup(), 那么祖先节点的值仍是旧值

    pushup()的目的是为了更新没有标记的祖先节点, 而不是有标记的点

    其实不pushup()应当是正确的:

    • 修改时, 从根节点沿途到最后一个节点都有pushdown()pushup()操作
    • 查询时, 如果遇到一个未pushdown()的节点, 说明他是修改/查询时的最后一个节点, 即祖先均被更新, 不需要pushup();而从这个节点继续往下推移, 就更新了沿途节点的值, 仍然不需要pushup()
    • 总结: 不需要pushup()

    BZOJ2002弹飞

    两棵树, 求(sum_i sum_j dis1[i][j]*dis2[i][j])

    dsu on tree http://codeforces.com/blog/entry/44351

    点分治树

    kdtree

    bzoj4566, 2870, 3277, 3926, 3473

  • 相关阅读:
    hdu2084 DP
    hdu 2080 夹角有多大(弧度制)
    hdu2078复习时间
    hdu2077
    hdu 2051
    hdu 2050
    hdu 5514Frogs
    ARM指令
    ARM寄存器
    树莓派ARM汇编
  • 原文地址:https://www.cnblogs.com/Kuonji/p/11839503.html
Copyright © 2020-2023  润新知