传送门

思路:
代码题
如果你已经做过一些扫描线的题目的话,这道题的思路一点都不难想:
不相交的图形→确定它们构成一棵树
如何确定这棵树→扫描线+set
set中的比较函数→圆直接代入方程计算,凸多边形相当于一坨线段,类似圆那样分成上下两部分,直接暴力枚举确定扫描线与哪条线段相交即可
询问坐标中的点→像处理图形那样来确定它们所在的是哪个图形
这样的话问题就转化成在一棵带边权的树上,每次查询两点的路径xor值或修改某一边权
直接链剖就可以了
……
其实上面说的都是些废话,因为做这道题的人肯定都知道思路大致是什么……

关键就是代码
显然这个题的代码不是那么好写的,下面我就来说说我写这个题的一些经历和体会
码完主体框架(5k+)大概用了1h~1.5h的时间,因为思路比较清楚简单所以没什么停顿
然后调试时发现了一些错误,比如凸多边形的上下部分计算出现问题,原本以为是点权树后来意识到是边权树等等
过了样例交上去发现RE,把数组开大后仍是RE
检查错误,手玩了几个点发现都能过(因为这个题的数据生成器和暴力对于我这个蒟蒻来说真是太TM难写了)
……
后来发现判断凸多边形的左右端点时条件不科学,导致死循环(怪不得内存达到了400MB+)
先说一下,我不是权限号,但之前打luogu的比赛,得到了可以要bzoj数据的奖励= =
于是偷偷要来了数据

发现计算交点时出现了玄学的错误,因为我为了避免讨论,在外面放了一个极大的圆
但是要到数据才发现,x,y,r的范围都是|109||10^9|,而long double的有效位数还不及long long,导致计算溢出,这就很尴尬了
改了下比较函数,又发现开方时出现了负数(??),以为是精度问题,加了个eps扰动,无果,发现差值大约为-0.18..,一度怀疑自己写错了
修改之后终于能跑出结果了,但发现只能过第十组数据,是一个圆套圆的数据(???)
发现又是比较函数的锅,而且似乎又出现了和memory一样的问题,a<ba,b<ab同时成立
结果就是一怒之下扔掉set,开始手写splay

代码也随之增长到了9k
写完以后发现splay和树结构的变量出现了重名(叫你不用namespace)
发现a<ba,b<ab
还是没有消除
又是一阵怒改比较函数,终于……
发现数据过了!

太过兴奋,没仔细看就交上去了,结果

感到十分不解,回头用人工二分,发现第45500+行出现了错误

调了一会,发现还是比较函数的错误,改过来以后在昨天晚自习下课前5min的时候A了
所以想写这道题的同学一定要写好比较函数啊啊啊啊
其实讲道理来说,这道题的思维难度并没有多大,但是对代码能力和思维清晰度要求很高,如果不能将自己的想法准确快速地转化成代码,这和没思路,写不了是同一个结果吧
我觉得这个题如果有人能在考场上得分,那就已经很厉害了,如果能A那就真的是大神……
(用vfk的话说,以上部分实际上是我的A后感)
其实我觉得下面给出的代码很符合知乎某大神的评论(找不到原话了,只能想起大体意思,如果有同学知道的话帮忙评论下谢谢)
“现在国内的大部分OI博客不适合学习,就是想炫耀一下自己A的代码而已”
代码:

#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
#include<cstring>
#define M 100005
using namespace std;
int n,m,tot,cnt,root,size;
double seg;
int first[M],fa[M<<1],top[M],son[M],siz[M],dep[M],dfn[M],pre[M],tr[M<<2],val[M],ch[M<<1][2],Fa[M];
char in()
{char ch=getchar();while (ch!='C'&&ch!='Q'&&ch!='P') ch=getchar();return ch;
}
typedef pair<double,double> Point;
Point tmp[M];
struct Poly{bool tp;//tp=0 表示凸多边形,opt=1 表示圆 int L,val;vector<Point> up,down;double x,y,r;
}a[M];
struct edge{int v,w,next;
}e[M<<1];
struct query{int opt;//opt=0 表示修改操作,opt=1 表示查询操作double x0,y0,x1,y1;int l,r;
}b[M];
struct os{int tp,id;double data;bool operator <(const os other)const{if (data==other.data) return tp>other.tp;return data<other.data;}
}c[M<<2];
int dcmp(double x,double y)
{if (fabs(x-y)<=1e-7) return 0;return x>y?1:-1;
}
double dis(int tp,int id)
{if (a[id].tp==1)if (tp)return a[id].y+sqrt(max(0.0,a[id].r*a[id].r-(seg-a[id].x)*(seg-a[id].x)));elsereturn a[id].y-sqrt(max(0.0,a[id].r*a[id].r-(seg-a[id].x)*(seg-a[id].x)));elseif (tp){int sz=a[id].up.size();for (int i=0;i<sz-1;++i)if (dcmp(a[id].up[i].first,seg)!=1&&dcmp(seg,a[id].up[i+1].first)!=1){if (!dcmp(a[id].up[i].first,a[id].up[i+1].first)) continue;double k=(a[id].up[i+1].second-a[id].up[i].second)/(a[id].up[i+1].first-a[id].up[i].first);return k*(seg-a[id].up[i].first)+a[id].up[i].second;}}else{int sz=a[id].down.size();for (int i=0;i<sz-1;++i)if (dcmp(a[id].down[i+1].first,seg)!=1&&dcmp(seg,a[id].down[i].first)!=1){if (!dcmp(a[id].down[i].first,a[id].down[i+1].first)) continue;double k=(a[id].down[i].second-a[id].down[i+1].second)/(a[id].down[i].first-a[id].down[i+1].first);return k*(seg-a[id].down[i+1].first)+a[id].down[i+1].second;}}
}
struct node{int tp,id;bool operator <(const node other)const{if (tp<2&&id==n+1) return tp;if (other.tp<2&&other.id==n+1) return !other.tp;if (tp<2&&other.tp<2&&other.id==id) return tp>other.tp;double t1,t2;if (tp==2) t1=b[id].y0;else if (tp==3) t1=b[id].y1;else t1=dis(tp,id);if (other.tp==2) t2=b[other.id].y0;else if (other.tp==3) t2=b[other.id].y1;else t2=dis(other.tp,other.id);return dcmp(t1,t2)==1;}bool operator ==(const node other)const{return tp==other.tp&&id==other.id;}
}Node[M<<1];
void add(int x,int y,int z)
{   e[++size]=(edge){y,z,first[x]};first[x]=size;e[++size]=(edge){x,z,first[y]};first[y]=size;
}
void rorate(int x,bool f)
{int y=fa[x];ch[y][!f]=ch[x][f];if (ch[x][f])fa[ch[x][f]]=y;fa[x]=fa[y];if (fa[y])if (ch[fa[y]][0]==y) ch[fa[y]][0]=x;else ch[fa[y]][1]=x;ch[x][f]=y;fa[y]=x;
}
void splay(int x,int goal)
{for (int y;fa[x]!=goal;){y=fa[x];if (fa[y]==goal)if (ch[y][0]==x) rorate(x,1);else rorate(x,0);else if (ch[fa[y]][0]==y){if (ch[y][0]==x) rorate(y,1);else rorate(x,0);rorate(x,1);}else{if (ch[y][1]==x) rorate(y,0);else rorate(x,1);rorate(x,0); }}if (!goal) root=x;
}
void insert(int x)
{if (!root) return void(root=x);int now=root;for (;;){if (Node[x]<Node[now])if (!ch[now][0]){ch[now][0]=x;fa[x]=now;break;}elsenow=ch[now][0];elseif (!ch[now][1]){ch[now][1]=x;fa[x]=now;break;}elsenow=ch[now][1];}splay(x,0);
}
int find(node x)
{int now=root;for (;now;){if (Node[now]==x) return now;if (Node[now]<x) now=ch[now][1];else now=ch[now][0];}
}
void erase(node x)
{int ID=find(x);splay(ID,0);if (!ch[ID][0]&&!ch[ID][1]) root=0;else if (!ch[ID][1]) root=ch[ID][0],fa[root]=0;else if (!ch[ID][0]) root=ch[ID][1],fa[root]=0;else{int now=ch[ID][0];while (ch[now][1]) now=ch[now][1];splay(now,root);ch[now][1]=ch[ID][1];fa[ch[ID][1]]=now;root=now;fa[root]=0;}
}
node Pre(node x)
{int now=root;node ans=(node){0,0};for (;now;){if (Node[now]<x){if (!ans.id||ans<Node[now]) ans=Node[now];now=ch[now][1];}elsenow=ch[now][0];}return ans;
}
node Sub(node x)
{int now=root;node ans=(node){0,0};for (;now;){if (x<Node[now]){if (!ans.id||Node[now]<ans) ans=Node[now];now=ch[now][0];}elsenow=ch[now][1];}return ans;
}
void init()
{for (int i=1;i<=m;++i)if (b[i].opt)c[++tot].data=b[i].x0,c[tot].id=i,c[tot].tp=2,c[++tot].data=b[i].x1,c[tot].id=i,c[tot].tp=3;Node[++cnt]=(node){1,n+1};insert(cnt);Node[++cnt]=(node){0,n+1};insert(cnt);sort(c+1,c+tot+1);for (int i=1;i<=tot;++i){seg=c[i].data;node tmp,t1,t2;tmp=(node){c[i].tp,c[i].id};t1=Pre(tmp);t2=Sub(tmp);if (c[i].tp>=2){int t;if (t1.id==t2.id) t=t1.id;else if (dep[t1.id]==dep[t2.id]) t=Fa[t1.id];else if (dep[t1.id]>dep[t2.id]) t=t2.id;else t=t1.id;if (c[i].tp==2) b[c[i].id].l=t;else b[c[i].id].r=t;}else if (c[i].tp){if (t1.id==t2.id)dep[c[i].id]=dep[t1.id]+1,Fa[c[i].id]=t1.id;else if (dep[t1.id]==dep[t2.id])dep[c[i].id]=dep[t1.id],Fa[c[i].id]=Fa[t1.id];else if (dep[t1.id]>dep[t2.id])dep[c[i].id]=dep[t1.id],Fa[c[i].id]=t2.id;elsedep[c[i].id]=dep[t2.id],Fa[c[i].id]=t1.id;add(c[i].id,Fa[c[i].id],a[c[i].id].val);Node[++cnt]=(node){1,c[i].id};insert(cnt);Node[++cnt]=(node){0,c[i].id};insert(cnt);}elseerase((node){1,c[i].id}),erase((node){0,c[i].id});}
}
void dfs1(int x)
{siz[x]=1;for (int i=first[x];i;i=e[i].next)if (e[i].v!=fa[x])fa[e[i].v]=x,dep[e[i].v]=dep[x]+1,val[e[i].v]=e[i].w,dfs1(e[i].v),siz[x]+=siz[e[i].v],son[x]=(!son[x]||siz[son[x]]<siz[e[i].v]?e[i].v:son[x]);
}
void dfs2(int x,int tp)
{dfn[x]=++dfn[0];pre[dfn[0]]=x;top[x]=tp;if (son[x]) dfs2(son[x],tp);for (int i=first[x];i;i=e[i].next)if (son[x]!=e[i].v&&fa[x]!=e[i].v)dfs2(e[i].v,e[i].v);
}
void build(int rt,int begin,int end)
{if (begin==end) return void(tr[rt]=val[pre[end]]);int mid=begin+end>>1;build(rt<<1,begin,mid);build(rt<<1|1,mid+1,end);tr[rt]=tr[rt<<1]^tr[rt<<1|1];
}
void update(int rt,int begin,int end,int pos,int val)
{if (begin==end) return void(tr[rt]=val);int mid=begin+end>>1;if (mid>=pos) update(rt<<1,begin,mid,pos,val);else update(rt<<1|1,mid+1,end,pos,val);tr[rt]=tr[rt<<1]^tr[rt<<1|1];
}
int get(int rt,int begin,int end,int l,int r)
{if (l<=begin&&end<=r) return tr[rt];int mid=begin+end>>1,ans=0;if (mid>=l) ans^=get(rt<<1,begin,mid,l,r);if (mid<r) ans^=get(rt<<1|1,mid+1,end,l,r);return ans;
}
main()
{ scanf("%d%d",&n,&m);for (int i=1;i<=n;++i)if (in()=='P'){a[i].tp=0;scanf("%d",&a[i].L);double xx,yy;int mi=-1,mx=-1;for (int j=0;j<a[i].L;++j)scanf("%lf%lf",&xx,&yy),tmp[j]=make_pair(xx,yy),mi=(mi==-1||tmp[mi].first>xx?j:mi),mx=(mx==-1||tmp[mx].first<xx?j:mx);for (int j=mi;j!=mx;j=(j+1)%a[i].L)a[i].up.push_back(tmp[j]);a[i].up.push_back(tmp[mx]);for (int j=mx;j!=mi;j=(j+1)%a[i].L)a[i].down.push_back(tmp[j]);a[i].down.push_back(tmp[mi]);c[++tot].tp=1;c[tot].data=tmp[mi].first;c[tot].id=i;c[++tot].tp=0;c[tot].data=tmp[mx].first;c[tot].id=i;scanf("%d",&a[i].val);}elsea[i].tp=1,scanf("%lf%lf%lf%d",&a[i].x,&a[i].y,&a[i].r,&a[i].val),c[++tot].tp=1,c[tot].data=a[i].x-a[i].r,c[tot].id=i,c[++tot].tp=0,c[tot].data=a[i].x+a[i].r,c[tot].id=i;for (int i=1;i<=m;++i)if (in()=='C')b[i].opt=0,scanf("%d%d",&b[i].l,&b[i].r);elseb[i].opt=1,scanf("%lf%lf%lf%lf",&b[i].x0,&b[i].y0,&b[i].x1,&b[i].y1);init();++n;dfs1(n);dfs2(n,n);build(1,1,n);int ans=0;for (int i=1;i<=m;++i)if (!b[i].opt)update(1,1,n,dfn[b[i].l],b[i].r);else{int x=b[i].l,y=b[i].r;for (;top[x]!=top[y];x=fa[top[x]]){if (dep[top[x]]<dep[top[y]]) swap(x,y);ans^=get(1,1,n,dfn[top[x]],dfn[x]);}if (dep[x]>dep[y]) swap(x,y);if (x!=y) ans^=get(1,1,n,dfn[son[x]],dfn[y]);printf("%d\n",ans);}
}

【BZOJ2758】Blinker的噩梦,扫描线+splay+链剖相关推荐

  1. 【codevs4632】【BZOJ4326】运输计划,链剖+二分+差分

    传送门1 传送门2 写在前面: 当初洗澡的时候脑补了下这个题,觉得很简单直到看到题面,才发现自己记错了,自此开始不归路 思路:这里的链剖实际上就是求每个操作的路径长度(也可以LCA求),然后我想到了二 ...

  2. [SHOI2012]魔法树 链剖

    都是链剖基础操作,注意开long long 码: #include<iostream> #include<cstdio> #include<vector> usin ...

  3. [BZOJ3631][JLOI2014]松鼠的新家(链剖)

    题目描述 传送门 题解 小傻逼手残 随便写链剖. 代码 #include<iostream> #include<cstring> #include<cstdio> ...

  4. 树链剖分(轻重链剖+长链剖)

    Part 0 一堆废话 本来树链剖分我是不打算写帖子的,因为我一道树剖的题都没做. 后面在刷树上启发式合并的题目时刚好遇到某道到现在都没调出来的题目要码树剖,感觉这道题在敲烂警钟提醒我好好学树剖,所以 ...

  5. bzoj4515 [Sdoi2016]游戏 标记永久线段树+链剖+差分

    树上路径问题还有一个比较好的差分就是利用到根节点的信息.. 题目的形式显然是一个一次函数,于是想到维护一次函数最小值 上升路径就是: A(d[x]-d[o])+B   =  -Ad[o]+(B-Ad[ ...

  6. bzoj3786星系探索 splay

    3786: 星系探索 Time Limit: 40 Sec  Memory Limit: 256 MB Submit: 1314  Solved: 425 [Submit][Status][Discu ...

  7. 【BZOJ3083】遥远的国度,树链剖分练习

    传送门 写在前面:链剖裸题里的战斗机 思路:Drusher向我推荐了这道污题,据说他请Claris调了一周才A,于是我怀着忐忑的心情开始看题,其他操作都好,一个换根把我搞懵逼了,"套spla ...

  8. 对LCA、树上倍增、树链剖分(重链剖分长链剖分)和LCT(Link-Cut Tree)的学习

    LCA what is LCA & what can LCA do LCA(Lowest Common Ancestors),即最近公共祖先 在一棵树上,两个节点的深度最浅的公共祖先就是 L ...

  9. 【Cf Edu #47 F】Dominant Indices(长链剖分)

    要求每个点子树中节点最多的层数,一个通常的思路是树上启发式合并,对于每一个点,保留它的重儿子的贡献,暴力扫轻儿子将他们的贡献合并到重儿子里来. 参考重链剖分,由于一个点向上最多只有$log$条轻边,故 ...

最新文章

  1. 安卓入门笔记之Activity
  2. 企业级工作流解决方案(八)--微服务Tcp消息传输模型之服务端处理
  3. Creo二次开发--内存清理函数
  4. [数据库]oracle导出数据库
  5. Exchange2003反病毒
  6. 高光谱提取薯叶特征波长
  7. threading.Event
  8. linux 2.6内核进程调度,linux2.6内核进程调度
  9. selenium控制浏览器
  10. struts2配置中因为包名问题遇到的No result defined for action错误
  11. apache rewrite支持post数据
  12. Excel进行灵敏度分析
  13. 柯马机器人示教器编程_COMAU柯马机器人示教器无显示维修过程
  14. Mac系统, 切换大小写失灵
  15. R语言与机器学习学习笔记(分类算法)(1)K-近邻算法
  16. Codecademy.com学习Python
  17. 高逼格技能教你玩转Excel
  18. 头文件中,#include使用引号“”和尖括号有什么区别?
  19. 2D shape decompositions二维形状分解
  20. MongoDB的客户端管理工具--nosqlbooster 连接MongoDB服务器

热门文章

  1. Reactive(3)5分钟理解 SpringBoot 响应式的核心-Reactor
  2. 韩顺平php视频笔记72-74 面向对象编程的三大特征3 重载override与重写overload 魔术常量
  3. 高等组合学笔记(八):第一类Stirling数, 整数分拆
  4. 计算机图形学E3——OpenGL 中点画圆
  5. 计算机教案解说词,解说词(教案)
  6. android引入开源项目方法,和解决android-support-v4.jar冲突问题
  7. python安装第三方库时报错 SyntaxError: invalid syntax
  8. linux系统取代windows,Linux不可能取代Windows
  9. 后台运行linux程序,后台运行Linux程序的方法
  10. 如何快速的入门git实现版本控制