icpc2018徐州OnlineG-Trace(线段树)

传送门

首先计算宽度,维护一棵线段树存之前扫描过的线段中时间比当前边大的长度

于是可以线段树下标为时间,值为长度,因为线段树要做到子节点的信息能往上传。如果下标为长度,值为时间,我们就不能动态地计算时间大于 t 时的长度!

ac代码:

#include<bits/stdc++.h>
#define per(i,a,b) for(int i=a;i<=b;i++)
#define mod 1000000007
using namespace std;
typedef long long ll;
//#define int long long
const int inf =0x3f3f3f3f;
const double eps=1e-8;
int read(){
    char ch=getchar();
    int res=0,f=0;
    while(ch<'0' || ch>'9'){f=(ch=='-'?-1:1);ch=getchar();}
    while(ch>='0'&&ch<='9'){res=res*10+(ch-'0');ch=getchar();}
    return res*f;
}
// ------------------------head
const int siz=5e4+5;
int n;
int tr[siz*4];//维护一棵时间线段树来存某时间前的长度
struct Node{
    int w,h,t;//w宽度  h高度
}node[siz];
bool cmp1(Node a,Node b){return a.h>b.h;}
bool cmp2(Node a,Node b){return a.w>b.w;}
int query(int u,int l,int r,int para){
    if(l>=para)return tr[u];
    int mid=l+r>>1;
    if(mid>=para)return max(query(u<<1,l,mid,para),query(u<<1|1,mid+1,r,para));
    else if(mid<para)return query(u<<1|1,mid+1,r,para);
}
void update(int u,int l,int r,int t,int v){
    if(l==r){tr[u]=max(tr[u],v);;return;}
    int mid=(l+r>>1);
    if(t<=mid)update(u<<1,l,mid,t,v);
    else if(t>mid)update(u<<1|1,mid+1,r,t,v);
    tr[u]=max(tr[u<<1],tr[u<<1|1]);
}

signed main()
{
    scanf("%d",&n);
    memset(tr,0,sizeof(tr));
    per(i,1,n){
        scanf("%d %d",&node[i].w,&node[i].h);
        node[i].t=i;
    }
    ll ans=0;
    sort(node+1,node+n+1,cmp1);
    for(int i=1;i<=n;i++){//按照高度排序,计算宽度
        int num=query(1,1,n,node[i].t);
        if(node[i].w>num){
            ans+=(ll)(node[i].w-num);
        }
        update(1,1,n,node[i].t,node[i].w);
    }
    memset(tr,0,sizeof(tr));
    sort(node+1,node+1+n,cmp2);
    for(int i=1;i<=n;i++){//按照宽度排序,计算高度
        int num=query(1,1,n,node[i].t);//num即按宽降序(前面的宽度都是更大的)后,前面出现的线段中高度最高的
        if(node[i].h>num)ans+=(ll)(node[i].h-num);
        update(1,1,n,node[i].t,node[i].h);
    }
    printf("%lld
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/WindFreedom/p/9637255.html