Atlantis
2 10 10 20 20 15 15 25 25.5 0
Test case #1 Total explored area: 180.00
矩形面积并入门题,
首先把直线拆成上边和下边,按高度排序,
横坐标离散化,建立线段树。
cnt[]表示某条线段被覆盖的次数,sum[]表示一条线段被覆盖的长度
我们在计算cnt[]时,没修改1个cnt[],就用pushup把sum[]更新,得到程序1:
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<cctype> #include<iostream> #include<functional> #include<algorithm> #include<map> using namespace std; #define MAXN (2000+10) #define MAXT (1000*2*10) #define Lson (x<<1) #define Rson ((x<<1)^1) int tt,n,size; double x[MAXN]; struct SegMent { double x1,x2,h; int type; SegMent(){} SegMent(double _x1,double _x2,double _h,int _type):x1(_x1),x2(_x2),h(_h),type(_type){} friend bool operator<(const SegMent a,const SegMent b){return a.h<b.h; } }a[MAXN]; map<double , int> hpos; double len[MAXT]; struct SegMentTree { int n,M,cnt[MAXT]; double sum[MAXT]; int mark[MAXT]; void fillchar(int _n) { n=_n; memset(cnt,0,sizeof(cnt)); memset(sum,0,sizeof(sum)); memset(mark,0,sizeof(mark)); M=1;while (M-2<n) M<<=1; x[0]=0;memset(len,0.0,sizeof(len)); for (int i=M+1;i<=M+size;i++) len[i]=x[i-M]-x[i-M-1]; for (int i=M-1;i>0;i--) len[i]=len[i<<1]+len[(i<<1)^1]; } void pushdown(int x) { if (x>>1) pushdown(x>>1); if (mark[x]) { mark[Lson]+=mark[x]; cnt[Lson]+=mark[x]; mark[Rson]+=mark[x]; cnt[Rson]+=mark[x]; mark[x]=0; } } void pushup(int x) { // pushdown(x);cout<<mark[5]; // cout<<x<<' '; sum[x]=cnt[x]?len[x]:(x>=M?0:sum[Lson]+sum[Rson]); } void update(int x) { for (;x;x>>=1) { // cout<<"push "<<x<<endl; pushup(x); } } void insert(int l,int r,int c) { int ll=l-1+M,rr=r+1+M; for (l=l-1+M,r=r+1+M,pushdown(l>>1),pushdown(r>>1);l^r^1;l>>=1,r>>=1) { if (~l&1) {cnt[l+1]+=c;update(l+1);/*mark[l+1]+=c;*/} /*改变sum的值 */ if (r&1) {cnt[r-1]+=c;update(r-1);/* mark[r-1]+=c;*/} } // update(ll);update(rr); //向上传递 } void print() { cout<<"cnt "; for (int i=1;i<=M*2;i++) if (cnt[i]) cout<<i<<':'<<cnt[i]<<' '; cout<<endl; cout<<"sum "; for (int i=1;i<=M*2;i++) if (sum[i]) cout<<i<<':'<<sum[i]<<' '; cout<<endl; cout<<"Mark "; for (int i=1;i<=M*2;i++) if (mark[i]) cout<<i<<':'<<mark[i]<<' '; cout<<endl; } }t; int main() { // freopen("Hdu1542.in","r",stdin); tt=0; while (scanf("%d",&n)!=EOF) { tt++; if (!n) break; for (int i=1;i<=2*n;i+=2) { scanf("%lf%lf%lf%lf",&a[i].x1,&a[i].h,&a[i].x2,&a[i+1].h); a[i+1].x1=a[i].x1; a[i+1].x2=a[i].x2; a[i].type=1;a[i+1].type=-1; x[i]=a[i].x1;x[i+1]=a[i].x2; } sort(a+1,a+2*n+1); // for (int i=1;i<=2*n;i++) cout<<a[i].x1<<' '<<a[i].x2<<' '<<a[i].h<<' '<<a[i].type<<endl; sort(x+1,x+2*n+1); size=unique(x+1,x+2*n+1)-(x+1); // for (int i=1;i<=size;i++) cout<<x[i]<<' ';cout<<endl; for (int i=1;i<=size;i++) hpos[x[i]]=i; t.fillchar(size); /* for (int i=1;i<=t.M*2;i++) cout<<len[i]<<' '; cout<<endl; */ /* t.insert(1,3,1);t.print(); t.insert(2,4,2); cout<<t.find(1,3); cout<<endl; t.print(); */ // t.insert(2,3,1); /* t.insert(2,3,1); t.print(); t.insert(3,4,1); t.print(); t.insert(2,3,-1); t.print(); */ double ans=0;a[0].h=a[1].h; for (int i=1;i<=2*n;i++) { ans+=(a[i].h-a[i-1].h)*t.sum[1]; t.insert(hpos[a[i].x1]+1,hpos[a[i].x2],a[i].type); /* t.print(); cout<<hpos[a[i].x1]+1<<' '<<hpos[a[i].x2]<<endl; cout<<t.sum[1]<<endl; cout<<ans<<endl; */ } printf("Test case #%dnTotal explored area: %.2lfnn",tt,ans); } return 0; }
上述程序效率较慢(m(logm)^2) ,m为边数
我们考虑到,每次上传实在太耗时了。
仔细观察方程,发现每次修改的点一定是从叶结点到根节点的路上的结点的兄弟(不包括路上)
因此每次被影响的一定是路上的结点。
故我们每次只更新结点的值,最后直接由根节点向上递归,得到程序2-效率为O(mlogm) :
#include<cstdio> #include<cstring> #include<cstdlib> #include<cmath> #include<cctype> #include<iostream> #include<functional> #include<algorithm> #include<map> using namespace std; #define MAXN (2000+10) #define MAXT (1000*2*10) #define Lson (x<<1) #define Rson ((x<<1)^1) int tt,n,size; double x[MAXN]; struct SegMent { double x1,x2,h; int type; SegMent(){} SegMent(double _x1,double _x2,double _h,int _type):x1(_x1),x2(_x2),h(_h),type(_type){} friend bool operator<(const SegMent a,const SegMent b){return a.h<b.h; } }a[MAXN]; map<double , int> hpos; double len[MAXT]; struct SegMentTree { int n,M,cnt[MAXT]; double sum[MAXT]; int mark[MAXT]; void fillchar(int _n) { n=_n; memset(cnt,0,sizeof(cnt)); memset(sum,0,sizeof(sum)); memset(mark,0,sizeof(mark)); M=1;while (M-2<n) M<<=1; x[0]=0;memset(len,0.0,sizeof(len)); for (int i=M+1;i<=M+size;i++) len[i]=x[i-M]-x[i-M-1]; for (int i=M-1;i>0;i--) len[i]=len[i<<1]+len[(i<<1)^1]; } void pushup(int x) { sum[x]=cnt[x]?len[x]:(x>=M?0:sum[Lson]+sum[Rson]); } void update(int x) { for (;x;x>>=1) { pushup(x); } } void insert(int l,int r,int c) { int ll=l-1+M,rr=r+1+M; for (l=l-1+M,r=r+1+M;l^r^1;l>>=1,r>>=1) { if (~l&1) {cnt[l+1]+=c;pushup(l+1);} /*改变sum的值 */ if (r&1) {cnt[r-1]+=c;pushup(r-1);} } update(ll);update(rr); } }t; int main() { // freopen("Hdu1542.in","r",stdin); tt=0; while (scanf("%d",&n)!=EOF) { tt++; if (!n) break; for (int i=1;i<=2*n;i+=2) { double x1,y1,x2,y2; scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2); x[i]=x1;x[i+1]=x2; a[i]=SegMent(x1,x2,y1,1); a[i+1]=SegMent(x1,x2,y2,-1); } sort(a+1,a+2*n+1); sort(x+1,x+2*n+1); size=unique(x+1,x+2*n+1)-(x+1); for (int i=1;i<=size;i++) hpos[x[i]]=i; t.fillchar(size); double ans=0;a[0].h=a[1].h; for (int i=1;i<=2*n;i++) { ans+=(a[i].h-a[i-1].h)*t.sum[1]; t.insert(hpos[a[i].x1]+1,hpos[a[i].x2],a[i].type); } printf("Test case #%dnTotal explored area: %.2lfnn",tt,ans); } return 0; }