CodeForces 286D

扫描线+线段树
扫描线处理墙壁的交,取最早出现时间
线段树算出每段墙壁对每个时间的贡献
对于[l,r,t]的墙壁
t-l+1以后出现的蚂蚁会完整走完[l,r],[t-l+1,1e9]的答案增加r-l+1

[t-r,t-l]成等差数列,线段树维护下就好

#include<cstdio>
#include<cstring>
#include<iostream>
#include<set>
#include<algorithm>
using namespace std;
const int N=1e5+100;
#define mid (l+r)/2

int add[N<<6],num[N<<6],lazy[N<<6],ls[N<<6],rs[N<<6],total;
int init(){
    num[total]=add[total]=lazy[total]=0;
    ls[total]=rs[total]=-1;
    return total++;
}

void down(int l,int r,int o){
    if(ls[o]==-1)ls[o]=init();
    if(rs[o]==-1)rs[o]=init();
    int ll=ls[o],rr=rs[o];

    add[ll]+=add[o];
    add[rr]+=add[o]+num[o]*(mid+1-l);

    num[ll]+=num[o];
    num[rr]+=num[o];

    lazy[ll]+=lazy[o];
    lazy[rr]+=lazy[o];

    num[o]=add[o]=lazy[o]=0;
}

int L,R,V,op;
void update(int l,int r,int o){
    if(L<=l&&r<=R){
        if(op==0){
            lazy[o]+=V;
        }
        else {
            add[o]+=l-L+1;
            num[o]++;
        }
        return ;
    }
    down(l,r,o);
    int ll=ls[o],rr=rs[o];
    if(L<=mid)update(l,mid,ll);
    if(R>mid)update(mid+1,r,rr);
}

int query(int l,int r,int o,int x){
    if(l==r){
        return add[o]+lazy[o];
    }
    down(l,r,o);
    int ll=ls[o],rr=rs[o];
    if(x<=mid)return query(l,mid,ll,x);
    else return query(mid+1,r,rr,x);
}

struct Node {
    int l,t,fg;
    Node(){}
    Node(int l,int t,int fg):l(l),t(t),fg(fg){}
    bool operator<(const Node & th)const {
        if(l!=th.l)return l<th.l;
        if(fg!=th.fg)return fg>th.fg;
        return t<th.t;
    }
}node[N*2];

int ll[N*4],rr[N*4],tt[N*4];
multiset<int> st;

int main(){
    #ifdef DouBi
    freopen("in.cpp","r",stdin);
    #endif // DouBi
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF){
        int tot=0;
        for(int i=0;i<m;i++){
            int l,r,t;scanf("%d%d%d",&l,&r,&t);r--;
//            if(l>r){
//                printf("%d %d %dlr\n",l,r,t);
//            }
            node[tot++]=Node(l,t,1);
            node[tot++]=Node(r,t,-1);
        }
        sort(node,node+tot);

        int cnt=0,pre;
        st.clear();
        for(int i=0;i<tot;i++){
            int l=node[i].l,t=node[i].t,fg=node[i].fg;
            //printf("%d %d %d\n",l,t,fg);
            if(st.size()==0){
                pre=l;
                st.insert(t);
                continue;
            }
            if(l>pre){
                ll[cnt]=pre;rr[cnt]=l-1;tt[cnt]=*st.begin();
                cnt++;
                pre=l;
            }
            if(fg==-1){
                if(pre==l){
                    ll[cnt]=pre;rr[cnt]=l;tt[cnt]=*st.begin();
                    cnt++;
                    pre=l+1;
                }
                //printf("%d %d\n",*st.lower_bound(t),t);
                st.erase(st.lower_bound(t));
            }
            else {
                st.insert(t);
            }
        }
//        for(int i=0;i<cnt;i++){
//            printf("%d %d %d\n",ll[i],rr[i],tt[i]);
//        }

        int ed=1e9;
        total=0;
        init();
        for(int i=0;i<cnt;i++){
            int l=ll[i],r=rr[i],t=tt[i];
            op=0;V=r-l+1;L=max(0,t-l+1),R=ed;
            //printf("%d %d\n",L,R);
            if(L<=R)update(0,ed,0);

            L=t-r,R=t-l;op=1;
            //printf("%d %d\n",l,r);
            if(R>=0)update(0,ed,0);
        }
        for(int i=0;i<n;i++){
            int a;scanf("%d",&a);
            printf("%d\n",query(0,ed,0,a));
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值