【BZOJ2584】memory,扫描线+拓扑图+骗
来源:互联网 发布:最霸气的帝王诗 知乎 编辑:程序博客网 时间:2024/05/21 05:43
传送门
思路:
神题
总结——写了一个错误做法,然后A了
想+写+调搞了将近一个星期
一开始想的是把斜着的线段转化成竖着的线段和横着的线段,然后分别做
但是好不容易打完以后,发现轻易就有反例(?)
然后先把题弃了,做了些简单题
学了圆的扫描线回来,发现这个题是可以用到的类似的思路,因为都是不相交的图形,可以通过交点的横纵坐标扔进set里搞一搞。
每添加进一个线段,就由它向它的前驱连边,由后继向它连边
每删除一个线段,就由它的后继向前驱连边
边数是
由于上下移动,左右移动正好是相反的,所以分别拿x,y为关键字扫两次就能建出4个拓扑图来了
关于第二问,显然只往一个方向移动肯定是有解的,而且这些线段的关系是一个DAG
然后就建了四个方向的DAG……
处理线段端点相交的话,坐标相等时再按照左右端点为关键字选就可以了
过了样例后交了上去,结果
最上边的两次是暴力向前驱后继连边,边数为
要来数据调,发现第2,3个点的第一问都过不了
那怎么跑的900ms+?
然后发现set出现了玄学的问题
yveh,ISA,DaD3zZ都过来看错误
最后yveh指出我的cmp函数竟然可以满足
同时我搞了个dcmp,再测试就过了
用数据测了下,第1问是没问题了,但是第二问应该依然是错误的
可是仔细思考一下,我发现我的做法是对于每个合法操作,在各个拓扑图里暴力删线段,这样会使在某一次操作中,可能图中还有限制当前移动操作的线段,但由于不是预处理时的前驱,就在图中没有连边,导致本来非法的操作被判断为合法
这个bug影响第一问,但应该是不会影响第二问的,因为我们只要按照拓扑排序的顺序进行输出,得到的操作一定是合法的
发现自己自作聪明,把第一问中合法的操作存起来当做第二问的答案,然后闷声改了过来
但并没有修改上述bug
结果
这个结果不奇怪,因为我把数据下下来了,发现自己第一问没错
这更让人感到奇怪,出题人连这个bug都没卡吗?
顺手打开连带数据一起发的std
发现std中有这样一行
然后std和我写的做法是一样的
所以这个神题就被我这么水过去了= =
还没完……
去问TA爷,TA给出了一个解决办法:如果要删的线段在图中有出度,就打个标记;如果没有出度,就删掉它,并且找指向它的线段,出度-1,然后再如上判断,递归做下去
由于脑抽+对TA爷的仰慕,开始着手搞这个东西
但调了好久才意识到,这个做法也有bug
因为x前驱的前驱,不一定是x的前驱!
也就是std中那句”拓扑不具有传递性“的那句话!
”我终于又想出了一个错误做法“ ——by TA
所以自己思考是很重要的,不要盲信他人,即使是TA
正确的题解:传送门
错误的代码:
#include<cstdio>#include<iostream>#include<algorithm>#include<cstring>#include<set>#include<queue>#include<cmath>#include<cstdlib>#define M 100005using namespace std;char *cp=(char *)malloc(20000000); int n,seg,tot[4],cnt;int A[M],B[M],C[M],D[M],first[4][M],deg[4][M],IN[M];double KK[M],BB[M];struct Point{ int data,tp,id;}a[M<<1];struct edge{ int v,next;}e[4][M*3];void add(int tp,int x,int y){ e[tp][++tot[tp]]=(edge){y,first[tp][x]}; first[tp][x]=tot[tp]; ++deg[tp][y];}double dis1(int id){return (seg-BB[id])/KK[id];}//求x double dis2(int id){return KK[id]*seg+BB[id];}//求y bool cmp(Point a,Point b){ if (a.data==b.data) return a.tp>b.tp; return a.data<b.data;}bool fcmp(double a,double b){ if (fabs(a-b)<=1e-7) return 0; return a>b;}struct node{ int tp,id;//tp=0->扫描线上下移动,tp=1->扫描线左右移动 bool operator <(const node other)const { if (!tp) return fcmp(dis1(id),dis1(other.id)); else return fcmp(dis2(id),dis2(other.id)); }};set<node> s;set<node>::iterator it1,it2;queue<int>q;inline int in () { int x=0,f=0; for (;*cp<'0'||*cp>'9';cp++) f|=((*cp)=='-'); for (x=0;*cp>='0'&&*cp<='9';cp++) x=x*10+*cp-48; return f?-x:x;}void work1()//点按照y排序,扫描线上下移动,set中按照交点的x排序 { for (int i=1;i<=n;++i) { a[i*2-1].data=B[i],a[i*2-1].tp=(B[i]>=D[i]); a[i*2].data=D[i],a[i*2].tp=(B[i]<D[i]); a[i*2-1].id=a[i*2].id=i; } sort(a+1,a+n*2+1,cmp); for (int i=1;i<=n<<1;++i) { seg=a[i].data; node tmp=(node){0,a[i].id},t1,t2; if (a[i].tp) { it1=s.lower_bound(tmp); it2=s.upper_bound(tmp); if (it1!=s.begin()&&it2!=s.end()) t1=*(--it1),t2=*it2, add(2,t1.id,t2.id), add(0,t2.id,t1.id); s.erase(tmp); } else { it1=s.lower_bound(tmp); it2=s.upper_bound(tmp); if (it2!=s.end()) t2=*it2, add(2,a[i].id,t2.id), add(0,t2.id,a[i].id); if (it1!=s.begin()) t1=*(--it1), add(2,t1.id,a[i].id), add(0,a[i].id,t1.id); s.insert(tmp); } }}void work2()//点按照x排序,扫描线左右移动,set中按照交点的y排序{ for (int i=1;i<=n;++i) a[i*2-1].data=A[i],a[i*2-1].tp=(A[i]>=C[i]), a[i*2].data=C[i],a[i*2].tp=(A[i]<C[i]), a[i*2-1].id=a[i*2].id=i; sort(a+1,a+n*2+1,cmp); s.clear(); for (int i=1;i<=n<<1;++i) { seg=a[i].data; node tmp=(node){1,a[i].id},t1,t2; if (a[i].tp) { it1=s.lower_bound(tmp); it2=s.upper_bound(tmp); if (it1!=s.begin()&&it2!=s.end()) t1=*(--it1),t2=*it2, add(1,t1.id,t2.id), add(3,t2.id,t1.id); s.erase(tmp); } else { it1=s.lower_bound(tmp); it2=s.upper_bound(tmp); if (it2!=s.end()) t2=*it2, add(1,a[i].id,t2.id), add(3,t2.id,a[i].id); if (it1!=s.begin()) t1=*(--it1), add(1,t1.id,a[i].id), add(3,a[i].id,t1.id); s.insert(tmp); } }}main(){ fread(cp,1,20000000,stdin); n=in(); for (int i=1;i<=n;++i) A[i]=in(),B[i]=in(),C[i]=in(),D[i]=in(), KK[i]=1.0*(B[i]-D[i])/(A[i]-C[i]), BB[i]=B[i]-KK[i]*A[i]; work1(); work2(); for (int i=1;i<=n;++i) IN[i]=deg[0][i]; for (int p,q,i=1;i<=n;++i) { p=in();q=in(); if (deg[q][p]) { printf("%d\n",i); break; } for (int tp=0;tp<4;++tp) for (int j=first[tp][p];j;j=e[tp][j].next) --deg[tp][e[tp][j].v]; } for (int i=1;i<=n;++i) if (!IN[i]) q.push(i); for (;!q.empty();q.pop()) { int k=q.front(); printf("%d %d\n",k,0); for (int i=first[0][k];i;i=e[0][i].next) { --IN[e[0][i].v]; if (!IN[e[0][i].v]) q.push(e[0][i].v); } }}
- 【BZOJ2584】memory,扫描线+拓扑图+骗
- [扫描线 线段树 拓扑排序] BZOJ2584 [Wc2012]memory
- [BZOJ2584][Wc2012]memory(扫描线+splay+线段树)
- 【BZOJ】【P2584】【Wc2012】【memory】【题解】【线段树+扫描线+拓扑排序】
- 拓扑图
- 拓扑图
- [Storm]用代码提交拓扑,自动从jar包中扫描拓扑实现接口
- 扫描线
- 扫描线
- 扫描线
- 扫描线
- 扫描线
- 扫描线
- 拓扑排序:图-拓扑排序
- Bayesian Network拓扑图
- flex拓扑图制作
- 网络拓扑图
- Flex 拓扑图
- HDU 1298 T9 字典树+dfs
- hdu 1465 不容易系列之一(错排模板)
- 百度地图BaiduMap--学习(三)------让自己的位置显示在地图上之“火星差”
- C语言:从键盘输入一个数n,求n的阶乘(n!)
- Java API操作hbase
- 【BZOJ2584】memory,扫描线+拓扑图+骗
- struts2中使用原生ajax请求后台数据
- struts2中的abstract
- jQuery EasyUI DataGrid - 格式化列(formatter )
- 日常生活小技巧 -- win10造字
- jmeter之——java压测
- apache2日志格式
- qq2689066360 真实姓名 谭绪武 黑客排行榜都是假的 在这里骗钱 大家不要上当 可以去我相册看证据
- WPF笔记一 关于XAML