P3740 [HAOI2014]贴海报
----------------------------
链接:Miku
----------------------------
这道题比想象的要水,虽然说标签有个离散化,但是事实上根本不用
但是这道题的空间范围很苛刻,倘若写记录每个点的左右子节点的线段树写法的话,可能会MLE
所以我写了不记录的写法,这样虽然会牺牲时间,但是节省了空间
而且这道题的空间,竟然开n*3就可以了
----------------------------
思路:海报之间是没有区别的,暴力的思路就是正着贴,最后计算一下露出来的种类就可以了
(虽然似乎也能够过)
但是其实可以倒着做,因为后面的如果能,就一定能覆盖前面的,这样的话我们就倒着贴每一张,然后看一下这一张的位置里
还有没有空,有空就贴上
怎样快速知道有没有空呢?每一个格子,如果贴上了,就标记为1,反之为0,这样我们求出来区间的和,与区间长度进行一下比较,就可以了,
如果有空,就把整个区间覆盖为1,(反正海报之间没有区别),然后ans++即可
----------------------------
区间覆盖+区间求和可以做一下这道题
-------------------------------
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int n,m; long long sum[30000005], lazy[30000005]; int f,x,y; long long k; int ans; int ll[1001],rr[1001]; void pushdown(int x, int L, int R){ if (lazy[x] != 0){ int mid = (L + R) >> 1; lazy[x << 1] = lazy[x]; lazy[x << 1 | 1] = lazy[x]; sum[x << 1] = lazy[x] * (mid - L + 1); sum[x << 1 | 1] = lazy[x] * (R - mid); lazy[x] = 0; } return; } void pushup(int x){ sum[x] = sum[x << 1] + sum[x << 1 | 1]; return; } void update(int x, int l, int r, int L, int R, long long d){ if (L <= l && r <= R){ lazy[x] =d; sum[x] = d * (r - l + 1); return; } int mid = (l + r) >> 1; pushdown(x, l, r); if (L <= mid) update(x << 1, l, mid, L, R, d); if (R > mid) update(x << 1 | 1, mid + 1, r, L, R, d); pushup(x); } long long query(int x, int l, int r, int L, int R){ if (L <= l && r <= R){ return sum[x]; } int mid = (l + r) >> 1; pushdown(x, l, r); long long ans = 0; if (L <= mid) ans += query(x << 1, l, mid, L, R); if (R > mid) ans += query(x << 1 | 1, mid + 1, r, L, R); return ans; } int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=m;++i){ cin>>ll[i]>>rr[i]; } for(int i=m;i>=1;--i){ x=ll[i]; y=rr[i]; if(query(1,1,n,x,y)<y-x+1){ update(1, 1, n, x, y,1); ans++; } } cout<<ans; return 0; }