题目大意:给n个桥,m次潮涨落,给定潮涨落的高度,问被淹没次数大于等于k的桥的个数,对于一直被淹没的,只记录一次。

把不同高度的桥看做坐标不同的点,然后潮涨落就相当于一次区间修改 修改的是上次潮落位置+1的桥到本次潮涨的位置,输出答案时需要访问到每个叶子结点。

AC代码

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
#define ls k<<1
#define rs k<<1|1
#define lson k<<1,l,mid
#define rson k<<1|1,mid+1,r
#define mid ((l+r)>>1)
#define laz(rt) tr[rt].laz
#define sum(rt) tr[rt].sum
const int maxn=100101;
int a[maxn];
int ki,cnt,n,m;
struct node{
    int sum,laz;
}tr[maxn<<2];
inline int read(){
    int s=0,w=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
    return s*w;
}
inline void down(int k){
    sum(ls)+=laz(k);sum(rs)+=laz(k);
    laz(ls)+=laz(k);laz(rs)+=laz(k);
    laz(k)=0;
}
void build(int k,int l,int r){
    laz(k)=sum(k)=0;
    if(l==r)return ;
    build(lson);build(rson);
}
void change(int k,int l,int r,int x,int y,int v){
    if(x<=l&&y>=r){
        laz(k)+=v;sum(k)+=v;
        return ;
    }
    if(laz(k))down(k);
    if(x<=mid)change(lson,x,y,v);
    if(y>mid)change(rson,x,y,v);
}
int ask(int k,int l,int r){
    if(l==r)
        return sum(k)>=ki;
    if(laz(k))down(k);
    return ask(lson)+ask(rson);
}
int c[maxn],d[maxn],x,y;
int main(){
    while(scanf("%d%d%d",&n,&m,&ki)!=EOF){
        for(int i=1;i<=n;i++)
            a[i]=read();
        sort(a+1,a+n+1);
        build(1,1,n);
        d[0]=0;
        for(int i=1;i<=m;i++){
            c[i]=read();d[i]=read();
            x=lower_bound(a+1,a+n+1,d[i-1]+1)-a;
            y=upper_bound(a+1,a+n+1,c[i])-a;
            if(a[y]>c[i])y--;
            change(1,1,n,x,y,1);
        }
        printf("Case %d: %d\n",++cnt,ask(1,1,n));
    }
    return 0;
}
01-20 19:50