JZOJsenior3488.【NOIP2013模拟联考11】矩形(rect)
2017-12-13 19:33
381 查看
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 2001 using 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; }
相关文章推荐
- JZOJsenior3470.【NOIP2013模拟联考8】最短路(path)
- [jzoj]3472. 【NOIP2013模拟联考8】匹配(match)(AC自动机+DP)
- [jzoj]3479. 【NOIP2013模拟联考9】工作安排(work)
- [jzoj]3480. 【NOIP2013模拟联考9】阿Q的停车场(park)(线段树+堆)
- [jzoj]3486. 【NOIP2013模拟联考10】道路改建(rebuild)(缩环+Tarjan+拓扑+bitset记录状态)
- [jzoj3472]【NOIP2013模拟联考8】匹配(match)
- [jzoj]3468. 【NOIP2013模拟联考7】OSU!(osu) (期望DP)
- JZOJ 3498【NOIP2013模拟联考14】图形变换
- JZOJ3501. 【NOIP2013模拟联考15】消息传递
- jzoj. 3450. 【NOIP2013模拟联考3】山峰(summits)
- JZOJsenior3455.【NOIP2013模拟联考3】库特的向量(code)
- 【JZOJ 3492】【NOIP2013模拟联考12】数数(count)
- [jzoj]3498. 【NOIP2013模拟联考14】图形变换(transform) (计算几何+矩阵乘法)
- JZOJ 3468. 【NOIP2013模拟联考7】OSU!(osu)
- JZOJ3455. 【NOIP2013模拟联考3】库特的向量(code)
- [jzoj]3457. 【NOIP2013模拟联考3】沙耶的玩偶(doll)(匈牙利-二分图最大匹配)
- JZOJ 3447【NOIP2013模拟联考2】摘取作物
- jzoj3450【NOIP2013模拟联考3】山峰(summits,dfs)
- jzoj 3467. 【NOIP2013模拟联考7】最长上升子序列(lis) dfs+lis+手工栈
- jzoj3501 【NOIP2013模拟联考15】消息传递(news) 树形dp