传送门
思路:
代码题
如果你已经做过一些扫描线的题目的话,这道题的思路一点都不难想:
不相交的图形→确定它们构成一棵树
如何确定这棵树→扫描线+set
set中的比较函数→圆直接代入方程计算,凸多边形相当于一坨线段,类似圆那样分成上下两部分,直接暴力枚举确定扫描线与哪条线段相交即可
询问坐标中的点→像处理图形那样来确定它们所在的是哪个图形
这样的话问题就转化成在一棵带边权的树上,每次查询两点的路径xor值或修改某一边权
直接链剖就可以了
……
其实上面说的都是些废话,因为做这道题的人肯定都知道思路大致是什么……
关键就是代码
显然这个题的代码不是那么好写的,下面我就来说说我写这个题的一些经历和体会
码完主体框架(5k+)大概用了1h~1.5h的时间,因为思路比较清楚简单所以没什么停顿
然后调试时发现了一些错误,比如凸多边形的上下部分计算出现问题,原本以为是点权树后来意识到是边权树等等
过了样例交上去发现RE,把数组开大后仍是RE
检查错误,手玩了几个点发现都能过(因为这个题的数据生成器和暴力对于我这个蒟蒻来说真是太TM难写了)
……
后来发现判断凸多边形的左右端点时条件不科学,导致死循环(怪不得内存达到了400MB+)
先说一下,我不是权限号,但之前打luogu的比赛,得到了可以要bzoj数据的奖励= =
于是偷偷要来了数据
发现计算交点时出现了玄学的错误,因为我为了避免讨论,在外面放了一个极大的圆
但是要到数据才发现,x,y,r的范围都是 |109| ,而long double的有效位数还不及long long,导致计算溢出,这就很尴尬了
改了下比较函数,又发现开方时出现了负数(??),以为是精度问题,加了个eps扰动,无果,发现差值大约为-0.18..,一度怀疑自己写错了
修改之后终于能跑出结果了,但发现只能过第十组数据,是一个圆套圆的数据(???)
发现又是比较函数的锅,而且似乎又出现了和memory一样的问题, a<b , b<a 同时成立
结果就是一怒之下扔掉set,开始手写splay
代码也随之增长到了9k
写完以后发现splay和树结构的变量出现了重名(叫你不用namespace)
发现 a<b , b<a 还是没有消除
又是一阵怒改比较函数,终于……
发现数据过了!
太过兴奋,没仔细看就交上去了,结果
感到十分不解,回头用人工二分,发现第45500+行出现了错误
调了一会,发现还是比较函数的错误,改过来以后在昨天晚自习下课前5min的时候A了
所以想写这道题的同学一定要写好比较函数啊啊啊啊
其实讲道理来说,这道题的思维难度并没有多大,但是对代码能力和思维清晰度要求很高,如果不能将自己的想法准确快速地转化成代码,这和没思路,写不了是同一个结果吧
我觉得这个题如果有人能在考场上得分,那就已经很厉害了,如果能A那就真的是大神……
(用vfk的话说,以上部分实际上是我的A后感)
其实我觉得下面给出的代码很符合知乎某大神的评论(找不到原话了,只能想起大体意思,如果有同学知道的话帮忙评论下谢谢)
“现在国内的大部分OI博客不适合学习,就是想炫耀一下自己A的代码而已”
代码:
#include
#include
#include
#include
#include
#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 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.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)));
else
return a[id].y-sqrt(max(0.0,a[id].r*a[id].r-(seg-a[id].x)*(seg-a[id].x)));
else
if (tp)
{
int sz=a[id].up.size();
for (int i=0;i1;++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;i1;++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]if (!ch[now][0])
{ch[now][0]=x;fa[x]=now;break;}
else
now=ch[now][0];
else
if (!ch[now][1])
{ch[now][1]=x;fa[x]=now;break;}
else
now=ch[now][1];
}
splay(x,0);
}
int find(node x)
{
int now=root;
for (;now;)
{
if (Node[now]==x) return now;
if (Node[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]if (!ans.id||ans1];
}
else
now=ch[now][0];
}
return ans;
}
node Sub(node x)
{
int now=root;
node ans=(node){0,0};
for (;now;)
{
if (xif (!ans.id||Node[now]0];
}
else
now=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;
else
dep[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);
}
else
erase((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]].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 (mid1|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.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].firstfor (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);
}
else
a[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);
else
b[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]]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);
}
}