zoukankan      html  css  js  c++  java
  • 「SDOI2009」虔诚的墓主人

    传送门
    Luogu

    解题思路

    离散化没什么好说
    有一种暴力的想法就是枚举每一个坟墓,用一些数据结构维护一下这个店向左,向右,向上,向下的常青树的个数,然后用组合数统计方案。
    但是网格图边长就有 (1e9) 级别,于是这种方法就萎了。
    考虑从常青树下手。
    我们可以发现在同一竖排中的两颗相邻的常青树之间的坟墓在纵方向的贡献是一样的。
    所以我们维护每一竖排的常青树,每一横排的贡献用线段树维护即可。

    细节注意事项

    • 咕咕咕

    参考代码

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdlib>
    #include <cstdio>
    #include <cctype>
    #include <cmath>
    #include <ctime>
    #include <vector>
    #define rg register
    using namespace std;
    template < typename T > inline void read(T& s) {
     	s = 0; int f = 0; char c = getchar();
     	while (!isdigit(c)) f |= (c == '-'), c = getchar();
     	while (isdigit(c)) s = s * 10 + (c ^ 48), c = getchar();
     	s = f ? -s : s;
    }
    
    typedef long long LL;
    const LL p = 2147483648;
    const int _ = 100010;
    
    int n, k, c[12][_];
    int xx, yy, X[_], Y[_];
    vector < int > vec[_];
    struct node{ int x, y; }t[_];
    int sum[_ << 2], R[_ << 2], L[_ << 2], val[_];
    
    inline int lc(int rt) { return rt << 1; }
    
    inline int rc(int rt) { return rt << 1 | 1; }
    
    inline void pushup(int rt) { sum[rt] = (sum[lc(rt)] + sum[rc(rt)]) % p; }
    
    inline void build(int rt = 1, int l = 1, int r = yy) {
    	if (l == r) { R[rt] = val[l]; return ; }
    	int mid = (l + r) >> 1;
    	build(lc(rt), l, mid), build(rc(rt), mid + 1, r);
    }
    
    inline void update(int id, int rt = 1, int l = 1, int r = yy) {
    	if (l == r) {
    		--R[rt], ++L[rt], sum[rt] = 1ll * c[k][L[rt]] * c[k][R[rt]] % p;
    		return ;
    	}
    	int mid = (l + r) >> 1;
    	if (id <= mid) update(id, lc(rt), l, mid);
    	else update(id, rc(rt), mid + 1, r);
    	pushup(rt);
    }
    
    inline LL query(int ql, int qr, int rt = 1, int l = 1, int r = yy) {
    	if (ql <= l && r <= qr) return sum[rt];
    	int mid = (l + r) >> 1; LL res = 0;
    	if (ql <= mid) res = (res + query(ql, qr, lc(rt), l, mid)) % p;
    	if (qr > mid) res = (res + query(ql, qr, rc(rt), mid + 1, r)) % p;
    	return res;
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
    	freopen("in.in", "r", stdin);
    #endif
    	read(n), read(n), read(n);
    	for (rg int i = 1; i <= n; ++i) {
    		read(t[i].x), X[i] = t[i].x;
    		read(t[i].y), Y[i] = t[i].y;
    	}
    	sort(X + 1, X + n + 1), xx = unique(X + 1, X + n + 1) - X - 1;
    	for (rg int i = 1; i <= n; ++i) t[i].x = lower_bound(X + 1, X + xx + 1, t[i].x) - X;
    	sort(Y + 1, Y + n + 1), yy = unique(Y + 1, Y + n + 1) - Y - 1;
    	for (rg int i = 1; i <= n; ++i) t[i].y = lower_bound(Y + 1, Y + yy + 1, t[i].y) - Y;
    	read(k), c[0][0] = 1;
    	for (rg int i = 1; i <= n; ++i) {
    		++val[t[i].y], vec[t[i].x].push_back(t[i].y);
    		c[0][i] = 1;
    		for (rg int j = 1; j <= k; ++j)
    			c[j][i] = (c[j][i - 1] + c[j - 1][i - 1]) % p;
    	}
    	build();
    	LL res = 0;
    	for (rg int i = 1; i <= xx; ++i) {
    		sort(vec[i].begin(), vec[i].end());
    		if (!vec[i].empty()) update(vec[i][0]);
    		int siz = vec[i].size();
    		for (rg int j = 1; j < siz; ++j) {
    			if (vec[i][j - 1] + 1 <= vec[i][j] - 1 && j >= k && siz - j >= k)
    				res = (res + 1ll * query(vec[i][j - 1] + 1, vec[i][j] - 1) * c[k][j] % p * c[k][siz - j] % p) % p;
    			update(vec[i][j]);
    		}
    	}
    	printf("%lld
    ", res);
    	return 0;
    }
    
    

    完结撒花 (qwq)

  • 相关阅读:
    算分-DESIGN THECHNIQUES
    高级数据结构笔记摘要
    红黑树和AVL树笔记摘要
    索引笔记摘要
    检索笔记摘要
    外排序笔记摘要
    内排序笔记摘要
    线性表总结
    数论的一点前置知识
    线段交模板
  • 原文地址:https://www.cnblogs.com/zsbzsb/p/11746086.html
Copyright © 2011-2022 走看看