BZOJ 2758 Blinker的噩梦(扫描线+熟练剖分+树状数组)
题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2758
题意:平面上有n个多边形(凸包和圆)。任意两个多边形AB只有两种关系:(1)A包含B或者B包含A;(2)AB的公共面积为0。每个多边形有一个值x。m个查询。分两种:(1)修改某个多边形的值;(2)从一点s走到另一点t。每次走出一个多边形或者进入一个多边形时,都要抑或上该多边形的值。输出走到t时的值。(由抑或的性质和本题定义可得这个值跟走的路经无关)
思路:首先我们发现,这些多边形构成了一棵树。另外设定义某一点p的值S(p)等于包含该点的所有多边形的值的抑或。那么答案为S(s)^S(t)。对应于那个树上,就是s和t到根的值的抑或和。如果我们建成了这棵树,那么分别维护:(1)修改某点的值;(2)查询某点到根的抑或值。这个可以用树链剖分,之后每个链用树状数组维护。
那么现在的问题来了,这个树怎么建?扫描线。保存多边形的最左最右。排序。按照x升序处理。维护包含当前x的所有多边形。维护的时候将要维护的多边形分成上下两部分。每个多边形的上部的标号就是自己,下部的标号为包含自己的最小多边形。每次假设从当前多边形向上有一条射线,那么第一次交到的就是包含该多边形的多边形(注意我们维护的信息是下部的标号为包含自己的最小多边形)。每次一个多边形不在当前要维护区间时删掉。
const double inf=1e20;
const int N=600005; struct point
{
double x,y;
point(double _x=0,double _y=0)
{
x=_x;
y=_y;
}
}; struct Figure
{
int type;
vector<point> up,down;
double x,y,r;
int v; pair<double,double> read()
{
char op[5];
scanf("%s",op);
if('C'==op[0])
{
type=0;
scanf("%lf%lf%lf%d",&x,&y,&r,&v);
return MP(x-r,x+r);
}
type=1;
vector<point> tmp;
double Min=inf,Max=-inf;
int minId,maxId;
int n=myInt();
for(int i=0;i<n;i++)
{
double x,y;
scanf("%lf%lf",&x,&y);
tmp.pb(point(x,y));
if(x>Max) Max=x,maxId=i;
if(x<Min) Min=x,minId=i;
}
if(maxId<minId)
{
for(int i=minId;i>=maxId;i--) down.pb(tmp[i]);
for(int i=minId;i<n;i++) up.pb(tmp[i]);
for(int i=0;i<=maxId;i++) up.pb(tmp[i]);
}
else
{
for(int i=minId;i<=maxId;i++) up.pb(tmp[i]);
for(int i=minId;i>=0;i--) down.pb(tmp[i]);
for(int i=n-1;i>=maxId;i--) down.pb(tmp[i]);
}
v=myInt();
return MP(Min,Max);
} int find(vector<point> a,double x)
{
for(int i=0;i+1<a.size();i++)
{
if(a[i].x<=x&&x<=a[i+1].x) return i;
}
}
double intersect(point L,point R,double x)
{
return L.y+(x-L.x)/(R.x - L.x)*(R.y-L.y);
}
double getInterval(double xx,int dir)
{
if(0==type)
{
if(fabs(xx-(x-r))<=0.001||fabs(xx-(x+r))<=0.001)
{
return y;
}
double tmp=sqr(r)-sqr(x-xx);
double d=sqrt(tmp);
if(dir) return y+d;
return y-d;
}
if(xx==up[0].x||xx==up.back().x)
{
double Max=-inf,Min=inf;
for(int i=0;i<up.size();i++) if(xx==up[i].x) Max=max(Max,up[i].y);
for(int i=0;i<down.size();i++) if(xx==down[i].x) Min=min(Min,down[i].y);
if(!dir) return Min;
return Max;
}
if(dir)
{
int u=find(up,xx);
return intersect(up[u],up[u+1],xx);
}
int d=find(down,xx);
return intersect(down[d],down[d+1],xx);
}
}; struct Query
{
int type,l,r;
};
struct sweepPoint
{
double x;
int id,dir; sweepPoint(double _x=0,int _id=0,int _dir=0)
{
x=_x;
id=_id;
dir=_dir;
}
}; Figure G[N];
sweepPoint Q[N];
int qNum;
Query query[N];
point p[N];
int pNum; int n,m; vector<int> g[N]; void add(int x,int y)
{
g[x].pb(y);
} double curX; struct myPair
{
int id,dir,belong; myPair(double id=0,int dir=0,int belong=0)
{
this->id=id;
this->dir=dir;
this->belong=belong;
} friend int operator<(const myPair &a,const myPair &b)
{
if(a.id==b.id&&a.dir!=2&&b.dir!=2) return a.dir<b.dir;
double x=(2==a.dir)?p[a.id].y:G[a.id].getInterval(curX,a.dir);
double y=(2==b.dir)?p[b.id].y:G[b.id].getInterval(curX,b.dir);
return x<y;
}
}; set<myPair> T;
myPair L[N],R[N]; int cmp(sweepPoint a,sweepPoint b)
{
if(fabs(a.x-b.x)<1e-8) return a.dir<b.dir;
return a.x<b.x;
} void init()
{
sort(Q+1,Q+qNum+1,cmp); int K=n+pNum+1; for(int i=1;i<=qNum;i++)
{
curX=Q[i].x;
if(0==Q[i].dir)
{
myPair tmp=myPair(Q[i].id,1,Q[i].id);
T.insert(tmp);
R[Q[i].id]=tmp;
set<myPair>::iterator it=T.find(tmp);
it++;
int belong=it==T.end()?K:it->belong; tmp=myPair(Q[i].id,0,belong);
T.insert(tmp);
L[Q[i].id]=tmp;
add(belong,Q[i].id);
}
else if(1==Q[i].dir)
{
T.erase(L[Q[i].id]);
T.erase(R[Q[i].id]);
}
else if(2==Q[i].dir)
{
myPair tmp=myPair(Q[i].id,2,0);
set<myPair>::iterator it=T.lower_bound(tmp);
if(it==T.end()) add(K,Q[i].id+n);
else add(it->belong,Q[i].id+n);
}
}
} int d[N]; int son[N];
int fa[N]; void DFS(int u)
{
son[u]=1;
for(int i=0;i<SZ(g[u]);i++)
{
int v=g[u][i];
fa[v]=u;
DFS(v);
son[u]+=son[v];
}
} int pool[N];
int poolCount; int *S[N]; int pos[N],root[N],id,listLen[N]; void dfs(int u,int rt)
{
id++;
root[u]=rt;
pos[u]=id;
listLen[rt]++; int s=0;
for(int i=0;i<SZ(g[u]);i++)
{
int v=g[u][i];
if(son[v]>son[s]) s=v;
}
if(!s) return;
dfs(s,rt);
for(int i=0;i<SZ(g[u]);i++)
{
int v=g[u][i];
if(v!=s) dfs(v,v);
}
} void add(int rt,int x,int val)
{
while(x<=listLen[rt])
{
S[rt][x]^=val;
x+=x&-x;
}
} int cal(int t)
{
int rtPos=pos[root[t]];
int x=pos[t]-rtPos+1;
int rt=root[t]; int ans=0;
while(rt)
{
while(x) ans^=S[rt][x],x-=x&-x; int t=fa[rt];
int rtPos=pos[root[t]];
x=pos[t]-rtPos+1;
rt=root[t];
}
return ans;
} int main()
{
n=myInt();
m=myInt();
for(int i=1;i<=n;i++)
{
pair<double,double> tmp=G[i].read(); Q[++qNum]=sweepPoint(tmp.first,i,0);
Q[++qNum]=sweepPoint(tmp.second,i,1);
}
for(int i=1;i<=m;i++)
{
char op[5];
scanf("%s",op);
if('Q'==op[0])
{
pNum++; scanf("%lf%lf",&p[pNum].x,&p[pNum].y);
pNum++; scanf("%lf%lf",&p[pNum].x,&p[pNum].y);
query[i].type=1;
query[i].l=pNum-1;
query[i].r=pNum;
Q[++qNum]=sweepPoint(p[pNum-1].x,pNum-1,2);
Q[++qNum]=sweepPoint(p[pNum].x,pNum,2);
}
else
{
query[i].type=0;
scanf("%d%d",&query[i].l,&query[i].r);
}
}
init();
for(int i=1;i<=n;i++) d[i]=G[i].v;
DFS(n+pNum+1);
dfs(n+pNum+1,n+pNum+1); for(int i=1;i<=n+pNum+1;i++)
{
if(root[i]==i)
{
S[i]=pool+poolCount;
poolCount+=listLen[i]+2;
}
}
for(int i=1;i<=n;i++)
{
int rtPos=pos[root[i]];
int p=pos[i];
int x=p-rtPos+1;
add(root[i],x,d[i]);
}
int last=0;
for(int i=1;i<=m;i++)
{
if(0==query[i].type)
{
int t=query[i].l;
int rtPos=pos[root[t]];
int p=pos[t];
int x=p-rtPos+1;
add(root[t],x,d[t]);
d[t]=query[i].r;
add(root[t],x,d[t]);
}
else if(1==query[i].type)
{
int x=cal(query[i].l+n);
int y=cal(query[i].r+n);
last^=x^y;
printf("%d\n",last);
}
}
}
BZOJ 2758 Blinker的噩梦(扫描线+熟练剖分+树状数组)的更多相关文章
- hdu 3966 Aragorn's Story(树链剖分+树状数组/线段树)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3966 题意: 给出一棵树,并给定各个点权的值,然后有3种操作: I C1 C2 K: 把C1与C2的路 ...
- 【bzoj5173】[Jsoi2014]矩形并 扫描线+二维树状数组区间修改区间查询
题目描述 JYY有N个平面坐标系中的矩形.每一个矩形的底边都平行于X轴,侧边平行于Y轴.第i个矩形的左下角坐标为(Xi,Yi),底边长为Ai,侧边长为Bi.现在JYY打算从这N个矩形中,随机选出两个不 ...
- Aragorn's Story 树链剖分+线段树 && 树链剖分+树状数组
Aragorn's Story 来源:http://www.fjutacm.com/Problem.jsp?pid=2710来源:http://acm.hdu.edu.cn/showproblem.p ...
- [BZOJ 3295] [luogu 3157] [CQOI2011]动态逆序对(树状数组套权值线段树)
[BZOJ 3295] [luogu 3157] [CQOI2011] 动态逆序对 (树状数组套权值线段树) 题面 给出一个长度为n的排列,每次操作删除一个数,求每次操作前排列逆序对的个数 分析 每次 ...
- 4.12 省选模拟赛 LCA on tree 树链剖分 树状数组 分析答案变化量
LINK:duoxiao OJ LCA on Tree 题目: 一道树链剖分+树状数组的神题. (直接nQ的暴力有50. 其实对于树随机的时候不难想到一个算法 对于x的修改 暴力修改到根. 对于儿子的 ...
- HDU 3966 Aragorn's Story 树链剖分+树状数组 或 树链剖分+线段树
HDU 3966 Aragorn's Story 先把树剖成链,然后用树状数组维护: 讲真,研究了好久,还是没明白 树状数组这样实现"区间更新+单点查询"的原理... 神奇... ...
- bzoj1146整体二分+树链剖分+树状数组
其实也没啥好说的 用树状数组可以O(logn)的查询 套一层整体二分就可以做到O(nlngn) 最后用树链剖分让序列上树 #include<cstdio> #include<cstr ...
- HDU 5044 (树链剖分+树状数组+点/边改查)
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5044 题目大意:修改链上点,修改链上的边.查询所有点,查询所有边. 解题思路: 2014上海网赛的变 ...
- hdu 3966 Aragorn's Story(树链剖分+树状数组)
pid=3966" target="_blank" style="">题目链接:hdu 3966 Aragorn's Story 题目大意:给定 ...
随机推荐
- 夺命雷公狗---DEDECMS----5快速入门之商城快速搭建实现快递方式和支付方式的显示
我们现在用dedecms快速搭建一个商场,方法如下所示: 如此类推.写多几个栏目,效果 如下所示: 然后我们添加几个商品,记得要刷新下页面噢,不见见不到商品 添加成功后去看看效果如何: 出来了,但是如 ...
- Sinatra+SQLite3+DataMapper - 十分完整的tutorial - “Superdo”
原文地址:https://ididitmyway.herokuapp.com/past/2010/3/30/superdo_a_sinatra_and_datamapper_to_do_list/ 这 ...
- C++中关于无法解析的外部符号问题LNK2019问题的总结
网上一般有很全面的解决方法,最近恰好本道长也遇到了这种问题,也恰好解决了,这种问题应该算作配置问题,而非程序本身问题,多数是因为接手了生疏的程序导致,此问题看上去很简单,但木有经验的话很 ...
- Javascript之回调函数(callback)
1.回调函数定义: 回调函数就是一个通过函数指针调用的函数.如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数.回调函数不是由该函数的实现方 ...
- hadoop自带例子wordcount的具体运行步骤
1.在hadoop所在目录“usr/local”下创建一个文件夹input root@ubuntu:/usr/local# mkdir input 2.在文件夹input中创建两个文本文件file1. ...
- angular源码分析 摘抄 王大鹏 博客 directive指令及系列
链接地址:http://www.cnblogs.com/web2-developer/p/angular-14.html $compile的功能:将一个html字符串或者一个DOM进行编译,返回一个链 ...
- 【python cookbook】【数据结构与算法】12.找出序列中出现次数最多的元素
问题:找出一个元素序列中出现次数最多的元素是什么 解决方案:collections模块中的Counter类正是为此类问题所设计的.它的一个非常方便的most_common()方法直接告诉你答案. # ...
- ASP.NET MVC下的四种验证编程方式【转】
ASP.NET MVC采用Model绑定为目标Action生成了相应的参数列表,但是在真正执行目标Action方法之前,还需要对绑定的参数实施验证以确保其有效 性,我们将针对参数的验证成为Model绑 ...
- Git 使用规范流程
Git教程:http://www.liaoxuefeng.com/wiki/0013739516305929606dd18361248578c67b8067c8c017b000 团队开发中,遵循一个合 ...
- Nginx+Keepalived实现 转载
一.Keepalived简介 keepalived是一个类似于layer3, 4 & 5交换机制的软件,也就是我们平时说的第3层.第4层和第5层交换.Keepalived的作用是检测web服务 ...