这道题做得真心不容易,首先是离散化纠结了许久,然后就是线段树竟然还会写得有漏洞,最后就是数据范围了,这题的数据超强的啊,最后结果要用__int64,但我还是忽略了中间计算过程也会超范围,最后各种无语。。。
然后说下这题的思路吧,由于坐标的变化范围很大,而城市最多只有40000个(其实是400000个,奉献了几个re),所以很容易想到用离散化。离散化后接下来就是插入线段了,计算面积时当然就要知道这段的最大高度了。但此处有个小技巧,如果我们按照数据给定的顺序插的话,在插入的过程中我们就需要加判断,这样难免显得会很麻烦,因此我们可以对数据按照高度从小到大进行排序,再按这个顺序插入线段。
#include <iostream> #include<algorithm> #include<cstdio> using namespace std; const int maxn=40100; struct house { int l,r,h; bool operator<(const struct house t)const { return h<t.h; } }h[maxn];//离散化后的 struct pp { int id,key; bool isLeft; bool operator<(const struct pp t)const { return key<t.key; } }q[maxn*2];//离散化前的 struct node { __int64 l,r,h; }p[maxn*4]; int index[maxn];//映射数组 void build_tree(int l,int r,int rt) { p[rt].l=l; p[rt].r=r; p[rt].h=0; if(l==r-1) return; int mid=(l+r)>>1; build_tree(l,mid,rt<<1); build_tree(mid,r,rt<<1|1); } void init(int n) { int i,j,k; for(i=1,j=1;i<=n;i++) { scanf("%d",&q[j].key); q[j].isLeft=true; q[j].id=i; j++; scanf("%d",&q[j].key); q[j].isLeft=false; q[j].id=i; j++; scanf("%d",&h[i].h); } sort(q+1,q+j); for(i=1,k=0;i<j;i++) { if(q[i].key!=q[i-1].key) index[++k]=q[i].key; if(q[i].isLeft) h[q[i].id].l=k; else h[q[i].id].r=k; } sort(h+1,h+n+1);//对离散后的数据按高度排序 build_tree(1,k,1); } __int64 query(int rt) { if(p[rt].h) return p[rt].h*(index[p[rt].r]-index[p[rt].l]);//此处计算可能超范围 else if(p[rt].l==p[rt].r-1) return 0; return query(rt<<1)+query(rt<<1|1); } void insert(int l,int r,int d,int rt) { if(p[rt].l==l&&p[rt].r==r) { p[rt].h=d; return; } if(p[rt].h)//下传 { p[rt<<1].h=p[rt<<1|1].h=p[rt].h; p[rt].h=0; } int mid=(p[rt].l+p[rt].r)>>1; if(r<=mid) insert(l,r,d,rt<<1); else if(l>=mid) insert(l,r,d,rt<<1|1); else { insert(l,mid,d,rt<<1); insert(mid,r,d,rt<<1|1); } } int main() { int n; scanf("%d",&n); init(n); for(int i=1;i<=n;i++) insert(h[i].l,h[i].r,h[i].h,1); printf("%I64d\n",query(1)); return 0; } /* 5 1 5 10 2 6 30 3 7 20 4 6 15 5 10 5 */