ymc 2009/4/9 hdu 1828 picture 线段树 参考99年国家队IOI论文集 题目大意: 给定n个边与坐标轴平行的矩形,求这些矩形的覆盖的形状的周长。 思想: 把所有矩形的左右边按x轴坐标从小大大排列,并且标记是左边还是右边,存在line[]中。 扫描矩形的所有y坐标,排列,按照这些y坐标切割y轴,得到2*n-1条线段,存在y[]中, 用这2*n-1条线段建立线段树,跟节点为tree[1]。 扫描矩形的所有x坐标,排列。放在x[1]到x[2n-1], 并且x[0]=x[1](计算时不用考虑第一次特殊情况)。 扫描line[],如果line[i]为左边,则插入线段树,否则从线段树中删除。 插入算法:线段line[i]插入到tree[p]中 如果line[i]完全覆盖tree[p],插入到tree[p]的树根。 再考虑插入到tree[p]的左子树与右子树。 同时记录tree[p]的跟节点需要更新(update=false) 删除算法:从tree[p]中删除line[i] 如果tree[p]完全被line[i]覆盖,从树根中删除。 再考虑从左子树与又子树中删除。 同时记录跟节点需要更新。 更新算法:更新树tree[p] 若tree被完全覆盖(count>0) 则 len=tree[p]的代表的线段的长度 否则 初始ans=0(周长); 每次插入或者删除线段line[i]时,同时计算ans的增长。具体如下: ans+=tree[1].lines*2*(x[i+1]-x[i1]) ans+=2*(更新信息前后,tree[1]中测度差的绝对值) */ #include <iostream> #include <vector> #include <algorithm> #include <cmath> using namespace std; const int N=20000; struct Line //表示平行与y轴的边 { bool operator <(const Line t) const { return x<t.x; }; struct Node//线段树的节点 { // int l,r; }; Node tree[4*N]; Line line[2*N]; int x[2*N],y[2*N];//x,y轴上的分割点, int n; void Build(int p,int left,int right)//left,right为y轴上分割点的下标 { } void Insert(int p,int l,int r,int y1,int y2) { if(y1<=y[l]&&y[r]<=y2)//覆盖整个树p { if(y1<y[m])//插入到左子树 { if(y[m]<y2)//插入到右子树 { } void Delete(int p,int l,int r,int y1,int y2) { if(y1<=y[l]&&y[r]<=y2)//从跟中删除 { if(y1<y[m])//从左子树中删除 { if(y[m]<y2)//从右子树中删除 { } void Update(int p,int l,int r) { if(tree[p].count>0)//被完全覆盖 { if(tree[2*p].rcover&&tree[2*p+1].lcover) } void Init() { for(int i=1;i<=n;i++) { scanf("%d%d%d%d",&x1,&y1,&x2,&y2); k=2*i-2; x[k+1]=x1;//预留x[0] x[k+2]=x2; y[k]=y1; y[k+1]=y2; line[k].y1=line[k+1].y1=y1; line[k].y2=line[k+1].y2=y2; line[k].x=x1; line[k].left=true; line[k+1].x=x2; line[k+1].left=false; } void Solve() { for(int i=0;i<2*n;i++)//对所有线段插入或者删除。因为x[0]==x[1],直接处理 { } int main() { while(scanf("%d",&n)!=EOF) { }
}
int m=(left+right)/2; Build(2*p,left,m); Build(2*p+1,m,right);
} if(l==r-1)
int m=(l+r)/2;
}
}
} if(l==r-1)
int m=(l+r)/2;
}
}
} else if(l==r-1) //叶节点并且count==0 {
} else//不是也节点并且没被完全覆盖 {
}
} sort(x+1,x+2*n+1); x[0]=x[1];//在出入与删除时,不需要特殊处理第一个线段 sort(y,y+2*n); sort(line,line+2*n);
} printf("%d\n",ans);
else
ans+=tree[1].lines*2*(x[i+1]-x[i]);//上下边数*长度 Lastlen=tree[1].len; Update(1,0,r); ans+=fabs((float)Lastlen-tree[1].len);//左右边的长度
}
} Init(); Solve();