JZOJsenior3488.【NOIP2013模拟联考11】矩形(rect)
来源:互联网 发布:js set array 转换 编辑:程序博客网 时间:2024/06/05 10:45
problem
Description
因为对polo忍无可忍, dzf使用圣剑在地上划出了许多纵横交错的沟壑来泄愤。这些沟壑都严格与X轴平行或垂直。
polo嘲笑了dzf无聊的行为,然后做了一件更加无聊的事。他蹲下来数这些沟壑的条数。数着数着,polo意识到一个问题,那就是因为圣剑的威力太大,划出的沟壑太多,地面就会塌陷。而如果两条水平的沟壑和两条垂直的沟壑相交组成了一个矩形,那么塌陷的危险就会进一步增加。现在polo已经数了n条沟壑,他想知道这些沟壑组成了多少个矩形。
Input
第一行一个数n,接下来每行4个数x1,y1,x2,y2,表示沟壑的两个端点(x1,y1),(x2,y2)
Output
一个数,组成的矩形个数。
Sample Input
输入1:
4
0 0 1 0
0 0 0 1
1 1 1 -1
1 1 0 1
输入2:
8
1 0 4 0
2 1 2 0
0 0 0 3
2 2 2 3
3 3 3 -1
0 3 4 3
4 1 -1 1
3 2 -1 2
Sample Output
输出1:
1
输出2:
6
Data Constraint
对于30%的数据,1<=n<=100
对于60%的数据,1<=n<=600
对于100%的数据,1<=n<=2000,坐标绝对值小于10^9,任意两条与X轴水平的沟壑之间没有交点,任意两条与X轴垂直的沟壑没有交点。
analysis
很经典的一道求平面内矩形数量的题目
但是我要插入一点东西
奇怪的东西:水法?
40%的数据,
O(n4) 枚举两条水平和两条垂直线段,傻子都会60%的数据,也很好想:枚举两条垂直的线段,枚举一条水平的线段
设都与两条垂直线段相交的水平线段的数量为
k ,那么明显能构成C(k,2)=k(k−1)2 个矩形结果一堆人用
O(n3) 的水法切掉了……切掉了……下面来看看这奇妙的水法代码
水法code
#include<cstdio>struct rec{int u,v,x,y;}a[2001],b[2001];bool pd[2001][2001];int n,u,v,x,y,o,p,f,w[2001][2001],c[2001];__attribute__((optimize("-O3")))bool in(int l,int x,int r){return l<=x&&x<=r;}__attribute__((optimize("-O3")))main(){ scanf("%d",&n); int i; for(i=1;i<=n;i++){ scanf("%d%d%d%d",&u,&v,&x,&y); if(y==v){//V == Y YZ if(u>x)f=u,u=x,x=f; a[++o]=rec{u,v,x,y}; }else{ if(v>y)f=v,v=y,y=f; b[++p]=rec{u,v,x,y};//U == X XZ } } int j,k,s=0,cnt,t0,t1; for(i=1;i<=o;i++) for(k=1;k<=p;k++) if(in(a[i].u,b[k].u,a[i].x)&&in(b[k].v,a[i].v,b[k].y)){ pd[i][k]=1; w[i][++c[i]]=k; } for(i=1;i<o;i++) for(j=i+1;j<=o;j++){ cnt=0; t0=i,t1=j; if(c[i]>c[j])t1=i,t0=j; for(k=1;k<=c[t0];k++) if(pd[t1][w[t0][k]])cnt++; s+=cnt*(cnt-1)/2; } printf("%d",s);}
哪位大爷看懂了,记得在评论区和我说一声啊
来点正常的吧
正解乃线段树
首先枚举一条垂直线段,把所有和这条线段相交的水平线段加进线段树
怎么加进线段树呢?把水平线段的
y 坐标离散化,从小到大排个序把第
i 号打上一个标记,表示第i 条水平线段与当前垂直线段相交然后我们本来要用一个
O(n) 循环来找k 的,现在用线段树的区间求和,O(log2n) 求解k 总时间复杂度
O(n2log2n) 虽说
n≤2000 ,但分开枚举水平垂直线段,时间达不到那么高所以线段树能在时间范围内跑出解
线段树code
#include<bits/stdc++.h>#define MAXN 2001using namespace std;int f[5*MAXN],li[5*MAXN],tree[5*MAXN];int n,x,n1,n2,len,tot;long long ans;struct information{ int x1,y1,x2,y2;}a[MAXN],b[MAXN],c[MAXN];bool cmp(information a,information b){ return a.x1<b.x1; }bool cmp1(information a,information b){ return a.x2<b.x2;}int query(int t,int l,int r,int x,int y){ if(x<=l && r<=y) { return tree[t]; } int mid=(l+r)/2; if(y<=mid) { return query(2*t,l,mid,x,y); } else if(x>mid) { return query(2*t+1,mid+1,r,x,y); } else { return query(2*t,l,mid,x,mid)+query(2*t+1,mid+1,r,mid+1,y); }}void change(int t,int l,int r,int x,int y){ if(l==r) { tree[t]+=y; return; } int mid=(l+r)/2; if(x<=mid) { change(2*t,l,mid,x,y); } else { change(2*t+1,mid+1,r,x,y); } tree[t]=tree[2*t]+tree[2*t+1];}int search(int t,int l,int r){ int mid=(l+r)/2; if(f[mid]==t) { return li[mid]; } if(t>f[mid]) { return search(t,mid+1,r); } else { search(t,l,mid-1); }}void init() { for(int i=1;i<=n1;i++) { f[++tot]=a[i].y1; f[++tot]=a[i].y2; } for(int i=1;i<=n2;i++) { f[++tot]=b[i].y1; f[++tot]=b[i].y2; } sort(f+1,f+tot+1); x=li[1]=1; for(int i=2;i<=tot;i++) { if(f[i]!=f[i-1])x++; li[i]=x; } for(int i=1;i<=n1;i++) { a[i].y1=search(a[i].y1,1,tot); a[i].y2=search(a[i].y2,1,tot); } for(int i=1;i<=n2;i++) { b[i].y1=search(b[i].y1,1,tot); b[i].y2=search(b[i].y2,1,tot); }}int find(int t,int l,int r){ if(l>r)return l; int mid=(l+r)/2; if(t>c[mid].x2) { return find(t,mid+1,r); } else { return find(t,l,mid-1); }}long long clam(long long x){ return x*(x-1)/2;}int main(){ //freopen("readin.txt","r",stdin); scanf("%d",&n); for(int i=1;i<=n;i++) { int x1,y1,x2,y2; scanf("%d%d%d%d",&x1,&y1,&x2,&y2); if(x1==x2) { a[++n1]={x1,y1,x2,y2}; if(a[n1].y1>a[n1].y2)swap(a[n1].y1,a[n1].y2); } else { b[++n2]={x1,y1,x2,y2}; if(b[n2].x1>b[n2].x2)swap(b[n2].x1,b[n2].x2); } } sort(a+1,a+n1+1,cmp); init(); for(int i=1;i<=n1;i++) { len=0; memset(tree,0,sizeof(tree)); for(int j=1;j<=n2;j++) if(a[i].y1<=b[j].y1 && b[j].y1<=a[i].y2 && b[j].x1<=a[i].x1 && a[i].x1<=b[j].x2) { c[++len]={b[j].x1,b[j].y1,b[j].x2,b[j].y2}; change(1,1,x,c[len].y1,1); } sort(c+1,c+len+1,cmp1); int last=1; for(int j=i+1;j<=n1;j++) if(a[j].x1>a[i].x1) { int t=find(a[j].x1,last,len); for(int k=last;k<t;k++) { change(1,1,x,c[k].y1,-1); } last=t; long long s=0; int up=min(a[i].y2,a[j].y2),down=max(a[i].y1,a[j].y1); if(down<=up) { s=query(1,1,x,down,up); } ans+=clam(s); } } printf("%lld\n",ans); return 0;}
- JZOJsenior3488.【NOIP2013模拟联考11】矩形(rect)
- 【NOIP2013模拟联考13】线段
- 【NOIP2013模拟联考7】数列
- 【NOIP2013模拟联考5】军训
- 【NOIP2013模拟联考6】选课
- 【NOIP2013模拟联考7】OSU
- JZOJsenior3487.【NOIP2013模拟联考11】剑与魔法(dragons)
- 【NOIP2013模拟联考5】军训(training)
- 【NOIP2013模拟联考6】选课(select)
- 【NOIP2013模拟联考5】军训(training) 题解
- NOIP2013模拟联考5】军训(training)
- 【NOIP2013模拟联考2】摘取作物(pick)
- 【NOIP2013模拟联考3】山峰(summits)
- 【NOIP2013模拟联考15】人类基因组(genes)
- 【NOIP2013模拟联考10】独立集(bubble)
- JZOJsenior3484.【NOIP2013模拟联考10】密码(substring)
- 【NOIP2013模拟联考14】图形变换(transform)
- 【NOIP2013模拟联考14】图形变换(transform)
- MySQL多实例从库show slave status卡死
- java-JFrame(JPanel面板)与常用组件
- 顺序查找,折半查找(递归与非递归)
- CSS和CSS3选择器
- HTML基础知识总结
- JZOJsenior3488.【NOIP2013模拟联考11】矩形(rect)
- 北京SEO祭司:天天更新网站内容怎么还没排名?
- easy-ui插件收获
- 第三章 RDD编程
- 二叉树的建立,以及递归前中后序遍历二叉树
- banner实现流+网络获取图片设置
- Linux下进程的创建
- 软件工程核心思想总结
- Android OTA系统升级---原理三