WC模拟(1.6) T1 送你一堆区间

送你一堆区间

题目背景:

1.8 WC模拟T1

分析:线段树优化DP

 

首先,考虑朴素意义下的DP,我们将区间端点变成覆盖的点集,然后按照左端点排序,考虑dp[i][j]表示,考虑到第i个区间,覆盖了前j个点的方案数,显然如果不选择那么直接考虑i - 1dp值,如果选择第i个区间,那么原来覆盖到l - 1r的方案数,就可以转移到dp[i][r]上,如果原来覆盖到r之后的,不会改变右端点位置,dp[i][j] += dp[i][j]就可以了,所以我们相当于将某一段的和加到某一个点上,然后区间乘2,那么拿线段树维护一下就可以了,复杂度O(nlogn)

 

Source:   

/*
	created by scarlyw
*/
#include <cstdio>
#include <string>
#include <algorithm>
#include <cstring>
#include <iostream>
#include <cmath>
#include <cctype>
#include <vector>
#include <set>
#include <queue>
#include <ctime>
#include <bitset>

inline char read() {
	static const int IN_LEN = 1024 * 1024;
	static char buf[IN_LEN], *s, *t;
	if (s == t) {
		t = (s = buf) + fread(buf, 1, IN_LEN, stdin);
		if (s == t) return -1;
	}
	return *s++;
}

///*
template<class T>
inline void R(T &x) {
	static char c;
	static bool iosig;
	for (c = read(), iosig = false; !isdigit(c); c = read()) {
		if (c == -1) return ;
		if (c == '-') iosig = true;	
	}
	for (x = 0; isdigit(c); c = read()) 
		x = ((x << 2) + x << 1) + (c ^ '0');
	if (iosig) x = -x;
}
//*/

const int OUT_LEN = 1024 * 1024;
char obuf[OUT_LEN], *oh = obuf;
inline void write_char(char c) {
	if (oh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout), oh = obuf;
	*oh++ = c;
}

template<class T>
inline void W(T x) {
	static int buf[30], cnt;
	if (x == 0) write_char('0');
	else {
		if (x < 0) write_char('-'), x = -x;
		for (cnt = 0; x; x /= 10) buf[++cnt] = x % 10 + 48;
		while (cnt) write_char(buf[cnt--]);
	}
}

inline void flush() {
	fwrite(obuf, 1, oh - obuf, stdout);
}

/*
template<class T>
inline void R(T &x) {
	static char c;
	static bool iosig;
	for (c = getchar(), iosig = false; !isdigit(c); c = getchar())
		if (c == '-') iosig = true;	
	for (x = 0; isdigit(c); c = getchar()) 
		x = ((x << 2) + x << 1) + (c ^ '0');
	if (iosig) x = -x;
}
//*/

const int MAXN = 500000 + 10;
const int mod = 1000000000 + 9;

int n, m;
int a[MAXN];

struct tree {
	int sum, tag;
} tree[MAXN << 2];

inline void add(int &x, int t) {
	x += t, (x >= mod) ? (x -= mod) : (x);
}

inline void mul_modify(int k, int x) {
	tree[k].sum = (long long)tree[k].sum * x % mod;
	tree[k].tag = (long long)tree[k].tag * x % mod;
}

inline void push_down(int k) {
	if (tree[k].tag != 1) {
		mul_modify(k << 1, tree[k].tag);
		mul_modify(k << 1 | 1, tree[k].tag);
		tree[k].tag = 1;
	}
}

inline void update(int k) {
	tree[k].sum = 0;
	add(tree[k].sum, tree[k << 1].sum), add(tree[k].sum, tree[k << 1 | 1].sum);
}

struct data {
	int l, r;
	inline bool operator < (const data &a) const {
		return (l == a.l) ? (r < a.r) : (l < a.l);
	}
} inter[MAXN];

inline int binary_l(int x) {
	int l = -1, r = m + 1;
	while (l + 1 < r) {
		int mid = l + r >> 1;
		(a[mid] >= x) ? r = mid : l = mid;
	}
	return r;
}

inline int binary_r(int x) {
	int l = 0, r = m + 1;
	while (l + 1 < r) {
		int mid = l + r >> 1;
		(a[mid] <= x) ? l = mid : r = mid;
	}
	return l;
}

inline void read_in() {
	R(n), R(m);
	for (int i = 1; i <= n; ++i) R(inter[i].l), R(inter[i].r);
	for (int i = 1; i <= m; ++i) R(a[i]);
	std::sort(a + 1, a + m + 1);
	for (int i = 1; i <= n; ++i) {
		inter[i].l = binary_l(inter[i].l);
		inter[i].r = binary_r(inter[i].r);
	}
	std::sort(inter + 1, inter + n + 1);
}

inline void build(int k, int l, int r) {
	tree[k].tag = 1, tree[k].sum = 0;
	if (l == r) return ;
	int mid = l + r >> 1;
	build(k << 1, l, mid), build(k << 1 | 1, mid + 1, r);
}

inline void modify(int k, int l, int r, int pos, int x) {
	if (l == r) return add(tree[k].sum, x);
	int mid = l + r >> 1;
	push_down(k);
	if (pos <= mid) modify(k << 1, l, mid, pos, x);
	else modify(k << 1 | 1, mid + 1, r, pos, x);
	update(k);
}

inline int query(int k, int l, int r, int ql, int qr) {
	if (ql <= l && r <= qr) return tree[k].sum;
	int mid = l + r >> 1, ret = 0;
	push_down(k);
	if (ql <= mid) add(ret, query(k << 1, l, mid, ql, qr));
	if (qr > mid) add(ret, query(k << 1 | 1, mid + 1, r, ql, qr));
	return update(k), ret;
}

inline void mul_modify(int k, int l, int r, int ql, int qr) {
	if (ql <= l && r <= qr) return mul_modify(k, 2);
	int mid = l + r >> 1;
	push_down(k);
	if (ql <= mid) mul_modify(k << 1, l, mid, ql, qr);
	if (qr > mid) mul_modify(k << 1 | 1, mid + 1, r, ql, qr);
	update(k);
}

inline void dfs(int k, int l, int r) {
	std::cout << l << " " << r << " " << tree[k].tag << " " << tree[k].sum << '\n';
	if (l == r) return ;
	int mid = l + r >> 1;
	dfs(k << 1, l, mid), dfs(k << 1 | 1, mid + 1, r);
}

inline void solve() {
	build(1, 0, m), modify(1, 0, m, 0, 1);
	for (int i = 1; i <= n; ++i) {
		int sum1 = query(1, 0, m, inter[i].l - 1, inter[i].r);
		if (inter[i].r != m) mul_modify(1, 0, m, inter[i].r + 1, m);
		modify(1, 0, m, inter[i].r, sum1);
	}
	std::cout << query(1, 0, m, m, m);
}

int main() {
	freopen("xmasinterval.in", "r", stdin);
	freopen("xmasinterval.out", "w", stdout);
	read_in();
	solve();
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值