题意很简单,n个桥的高度是事先给出来的,然后有m次涨水与落水的高度,问有多少座桥在这m次涨落之后 被淹超过了k次,如果某桥本身被水淹了,此时再涨水,就不能算多淹一次
看下数据10的五次方,10的五次方的硬循环是避免不了了,很明显在计算被淹次数的时候要能缩到logN的复杂度才好。
于是想到先对桥由低到高排一下序,然后获取前一次的落水值和这次的涨水值,只要桥高度在涨落直接的必定是又被淹了一次。要多次对序列的某个区间进行加操作,自然是线段树了,确定区间的时候,就用二分,在进行线段树的时候 用懒惰标记
#include <iostream> #include <cstring> #include <cstdio> #include <algorithm> #define Lson (rt<<1),l,mid #define Rson (rt<<1|1),mid+1,r #define N 100010 using namespace std; int n,m,k; int d[N*3],maxk[N*3],flag[N*3],A[N]; void up(int rt) { d[rt]=d[rt<<1]+d[rt<<1|1]; maxk[rt]=maxk[rt<<1]+maxk[rt<<1|1]; } void pushdown(int rt,int l,int r) { if (l>=r || flag[rt]==0) return; int ll=rt<<1; int rr=rt<<1|1; int mid=(l+r)>>1; d[ll]+=flag[rt]; d[rr]+=flag[rt]; flag[ll]+=flag[rt]; flag[rr]+=flag[rt]; flag[rt]=0; if (mid-l+1==1 && d[ll]>=k) maxk[ll]=1; if (r-mid==1 && d[rr]>=k) maxk[rr]=1; // up(rt); } void add(int rt,int l,int r,int L,int R) { if (L<=l && r<=R) { pushdown(rt,l,r); d[rt]+=r-l+1; if (l>=r && d[rt]>=k) maxk[rt]=1; flag[rt]++; return; } pushdown(rt,l,r); int mid=(l+r)>>1; if (L<=mid) add(Lson,L,R); if (R>mid) add(Rson,L,R); up(rt); } void incase(int rt,int l,int r) { if (l>=r) { if(d[rt]>=k) maxk[rt]=1; return; } pushdown(rt,l,r); int mid=(l+r)>>1; incase(Lson); incase(Rson); up(rt); } void build(int rt,int l,int r) { flag[rt]=0; if(l>=r) { d[rt]=0; maxk[rt]=0; flag[rt]=0; return; } int mid=(l+r)>>1; build(Lson); build(Rson); up(rt); } int main() { int kase=0,a,b,cur; while (scanf("%d%d%d",&n,&m,&k)!=EOF) { for (int i=1;i<=n;i++){ scanf("%d",&A[i]); } sort(A+1,A+1+n); build(1,1,n); cur=1; for (int i=1;i<=m;i++) { scanf("%d%d",&a,&b); int l=upper_bound(A+1,A+1+n,cur)-A; int r=upper_bound(A+1,A+1+n,a)-A; r--; if (l<=r) add(1,1,n,l,r); cur=b; } incase(1,1,n); printf("Case %d: %d ",++kase,maxk[1]); } return 0; }
好久没写线段树了,这个题一写完就WA了,后来发现,首先二分出来的区间先要判断下来,若区间不存在就不要进行插入了,还有就是pushdown,我一开始是计划每次只增加1
,要进行下一次懒惰标记的时候先把上一次 的懒惰标记down下去,结果在pushdown函数里面没判断儿子的标记,如果儿子标记了 也得先down儿子啊。结果这样超时了,还是不能这样,索性就每次懒惰标记直接++,最后把整个标记down下去就行
发现其实d数组完全没有必要的,这个值没有必要维护,只是一开始写的时候没计划的太清,就这样写了。其实没必要。
最后为了避免某个懒惰标记未被down下去,最后还用个incase函数再走一遍线段树,把值给更新一下。