hdu5861 Road,线段树,然后扫描

佣神给的思路

线段树预处理每一个road的起始和结束时间
然后排序按天数扫描,每天看有没有需要增加新路,看有没有需要关闭路
因为是排好序的,所以不会重复扫

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
const int N=600100;
int n,ans,m,a[N];
struct node {
    int l,r,id;
    node () { }
    node(int x,int y,int z){l=x;r=y;id=z;}
}b[N],c[N];
inline bool cmp1(node a,node b){return a.l<b.l;}
inline bool cmp2(node a,node b){return a.r<b.r;}

struct linetree{
    #define lc  (t<<1)
    #define rc  (t<<1^1)
    #define mid (l[t]+r[t]>>1)
    int l[N],r[N],ma[N],mi[N],M,ta[N],ti[N];
    inline void build(int n){
        M=1; while(M<n)M<<=1; M--;
        memset(ma, 0 ,sizeof(ma));
        memset(mi,INF,sizeof(mi));
        memset(ta, 0 ,sizeof(ta));
        memset(ti,INF,sizeof(ti));
        for (int i=1+M;i<=M*2+1;i++)l[i]=r[i]= i-M ;
        for (int t=M;t>=1;t--)l[t]=l[lc],r[t]=r[rc];
    }
    inline void down(int t){
        if (t>M)return ;//leaf node
        ma[lc]=max(ma[lc],ta[t]);
        ma[rc]=max(ma[rc],ta[t]);
        ta[lc]=max(ta[lc],ta[t]);
        ta[rc]=max(ta[rc],ta[t]);
        ta[t] = 0;

        mi[lc]=min(mi[lc],ti[t]);
        mi[rc]=min(mi[rc],ti[t]);
        ti[lc]=min(ti[lc],ti[t]);
        ti[rc]=min(ti[rc],ti[t]);
        ti[t] = INF;
    }
    inline void maintain(int t){
        ma[t]=max(ma[lc],ma[rc]);
        mi[t]=min(mi[lc],mi[rc]);
    }
    inline void tag(int t,int x){
        ma[t]=max(ma[t],x);
        mi[t]=min(mi[t],x);
        ta[t]=max(ta[t],x);
        ti[t]=min(ti[t],x);
    }
    void change(int t,int L,int R,int x){
        if (L<=l[t]&&r[t]<=R){tag(t,x);return;}
        down(t);
        if (L<=mid)change(lc,L,R,x);
        if (mid< R)change(rc,L,R,x);
        maintain(t);
    }
    void query(int t){
        if (t>M){//leaf node
            b[t-M]=c[t-M]=node(mi[t],ma[t],t-M);
            return ;
        }
        down(t);
        query(lc);
        query(rc);
        maintain(t);
    }
}T;

int main(){
    //freopen("fuck.in","r",stdin);
    int l,r;
    while (scanf("%d%d",&n,&m)==2){
        for (int i=1;i<n;i++)scanf("%d",&a[i]);
        T.build(n-1) ;
        for (int i=1;i<=m;i++){
            scanf("%d%d",&l,&r);
            if(l>=r) swap(l,r) ;
            T.change(1,l,r-1,i);
        }
        T.query(1);
        sort(b+1, b+n, cmp1);
        sort(c+1, c+n, cmp2);
        int x=1, y=1, ans=0 ;
        for (int i=1;i<=m;i++){
            for (; x<n &&b[x].l<=i;x++)
                if(b[x].l<=b[x].r)ans+=a[b[x].id];

            for (; y<n &&c[y].r< i;y++)
                if(c[y].l<=c[y].r)ans-=a[c[y].id];
            printf("%d\n" , ans);
        }
    }
    return 0;
}

多校训练结束啦,闷声滚大粗了
我好菜啊

其实,,因为是单点查询,而且所有点顺序查一次就行了
所以,,不需要tag,不需要maintain

新姿势

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int INF=0x3f3f3f3f;
const int N=600100;
int n,ans,m,a[N];
struct node {
    int l,r,id;
    node () { }
    node(int x,int y,int z){l=x;r=y;id=z;}
}b[N],c[N];
inline bool cmp1(node a,node b){return a.l<b.l;}
inline bool cmp2(node a,node b){return a.r<b.r;}

struct linetree{
    #define lc  (t<<1)
    #define rc  (t<<1^1)
    #define mid (l[t]+r[t]>>1)
    int l[N],r[N],ma[N],mi[N],M;
    inline void build(int n){
        M=1; while(M<n)M<<=1; M--;
        memset(ma, 0 ,sizeof(ma));
        memset(mi,INF,sizeof(mi));
        for (int i=1+M;i<=M*2+1;i++)l[i]=r[i]= i-M ;
        for (int t=M;t>=1;t--)l[t]=l[lc],r[t]=r[rc];
    }
    inline void down(int t){
        if (t>M)return ;//leaf node
        ma[lc]=max(ma[lc],ma[t]);
        ma[rc]=max(ma[rc],ma[t]);
        mi[lc]=min(mi[lc],mi[t]);
        mi[rc]=min(mi[rc],mi[t]);
    }
    inline void tag(int t,int x){
        ma[t]=max(ma[t],x);
        mi[t]=min(mi[t],x);
    }
    void change(int t,int L,int R,int x){
        if (L<=l[t]&&r[t]<=R){tag(t,x);return;}//in
        down(t);
        if (L<=mid)change(lc,L,R,x);
        if (mid< R)change(rc,L,R,x);
    }
    void query(int t){
        if (t>M){//leaf node
            b[t-M]=c[t-M]=node(mi[t],ma[t],t-M);
            return ;
        }
        down(t);
        query(lc);
        query(rc);
    }
}T;

int main(){
    //freopen("fuck.in","r",stdin);
    int l,r;
    while (scanf("%d%d",&n,&m)==2){
        for (int i=1;i<n;i++)scanf("%d",&a[i]);
        T.build(n-1) ;
        for (int i=1;i<=m;i++){
            scanf("%d%d",&l,&r);
            if(l>=r) swap(l,r) ;
            T.change(1,l,r-1,i);
        }
        T.query(1);
        sort(b+1, b+n, cmp1);
        sort(c+1, c+n, cmp2);
        int x=1, y=1, ans=0 ;
        for (int i=1;i<=m;i++){
            for (; x<n &&b[x].l<=i;x++)
                if(b[x].l<=b[x].r)ans+=a[b[x].id];
            for (; y<n &&c[y].r< i;y++)
                if(c[y].l<=c[y].r)ans-=a[c[y].id];
            printf("%d\n" , ans);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值