[Tricks-00009]bzoj3592 平面图剖分杂谈
可能会写不太清楚,见谅。
首先离线下来,把题目中的所有边都在二维平面上画出来,则一定是一个边双连通的平面剖分图。也就是,边都是线段的平面图,而且坐标都给好了。你可以通过经典做法(对所有点相邻的边极角排序,找出所有面建出对偶图,建个生成树)就可以刻画多边形内部所有面的性质了。
不过这道题它不!需!要!
为什么呢?因为题目只需要刻画点,没必要把面算完之后再绕回来去计算点。因此,关键的是,我们只需要求出一棵点生成树,根节点可以取一个确定在凸包上的点(例如,\(y\) 坐标最小的同时 \(x\) 坐标也要在其中最小,即只要达成这样的目标:最后走到根时不能还在一个多边形内部)。接下来,我们仿照传统的判点是否在多边形内的方法,给出一个针对平面图,更可爱的做法(其实是从 CF223E 学来的):
原本是从一点引出一条射线,判断交出的点数量是奇数还是偶数。实际上,我们没必要要求它是射线!任意一条折线其实都是 ok 的,也就是说,最方便的找法就是生成树上,该点到根的所有边,把它当作有向,从下往上。那么我们可以把从环上点走到环内点的边的贡献减 \(1\),从环内点走向环上点的加 \(1\)。这样你就会注意到,一个点在环内当且仅当这条路径上的权值和为 \(1\),不在就为 \(0\)。比如只去统计环内点权和的话,实际上环上的点给的贡献是独立的。如果你对树上每个点的儿子做了极角排序,则可以直接通过对极角二分来求出对应的区间,转成了至多两个 dfs 序上的连续段!
哦对了,刚才极角二分为什么是有道理的,给个说法:注意到,本题保证了给出的多边形是顺时针的,我不清楚这里顺时针怎么定义?不过有个判定是,叉积算面积后的值为负数。然后顺时针的性质似乎是,考虑一个顶点和它在多边形中连向的两条边,该点在其它时刻连出的边是否在多边形中,只要看极角是否在两条边对应的极角的有向区间内。因此,只要分别处理 \(L\leq R\) 和 \(L>R\) 的情况就好了。
回到原题,此时第一问已经做完了,但是看起来第二问不能通过直接拆贡献算。所以我们考虑换个思路。
这里就不唠闲嗑绕圈子了,直接给出最后结论:设多边形点数为 \(k\),则所有合法点在生成树极角排序后的 dfs 序上构成 \(O(k)\) 个连续段。
不过这也是好证明的。因为我们刚才那个做法,其实你先不要立刻算答案,就把权值挂在点上,+1/-1 和 ^1 是没区别的。因此就相当于,考虑序列差分,偶数段会有贡献,把这些拿出来就好了。
于是题目就变成了单点修改区间求和求最大值的问题,线段树维护十分轻松,复杂度一只 log,跑得不算慢。
其实还可以扩展到单边修改,多边形内所有边查询信息,有兴趣的读者可以思考一下,不难的。
给个代码:
#include<bits/stdc++.h>
using namespace std;
int x[50005],y[50005],d[50005];
int xx[50005],dd[50005],op[50005],m[50005];
vector<int>gg[50005],g[50005];
struct fenshu{
long long a,b;
fenshu(long long a=0,long long b=0):a(a),b(b){}
bool operator<(const fenshu &other)const{
return (__int128)a*other.b<(__int128)other.a*b;
}
};
fenshu getpi(int x,int y){
if(y>=0)return fenshu((x>0?1ll:-1ll)*x*x,1ll*x*x+1ll*y*y);
return fenshu(-(x>0?1ll:-1ll)*x*x-7*(1ll*x*x+1ll*y*y),1ll*x*x+1ll*y*y);
}
int vist[50005],fa[50005];
vector<pair<fenshu,int>>g2[50005];
void dfs0(int x,int la){
vist[x]=1;
for(auto cu:g[x]){
if(cu==la)continue;
if(vist[cu])continue;
fa[cu]=x;
dfs0(cu,x);
}
}
int bg[50005],en[50005],tot=0;
void dfs1(int x){
bg[x]=en[x]=++tot;
for(auto pi:g2[x]){
int cu=pi.second;
dfs1(cu);
en[x]=en[cu];
}
}
long long a[50005];
int pi[1000005],tt;
void jia(int l,int r,int x){
if(x==1||x==-1){
pi[++tt]=l;pi[++tt]=r+1;
}
}
long long ha,ma;
long long sm[200005],s2[200005];
void build(int l,int r,int o){
if(l==r){
sm[o]=s2[o]=a[l];
return;
}
int mid=(l+r)>>1;
build(l,mid,o<<1);build(mid+1,r,o<<1|1);
sm[o]=sm[o<<1]+sm[o<<1|1];s2[o]=max(s2[o<<1],s2[o<<1|1]);
}
void gai(int l,int r,int o,int x){
if(l==r){
sm[o]=s2[o]=a[l];
return;
}
int mid=(l+r)>>1;
if(x<=mid)gai(l,mid,o<<1,x);
else gai(mid+1,r,o<<1|1,x);
sm[o]=sm[o<<1]+sm[o<<1|1];s2[o]=max(s2[o<<1],s2[o<<1|1]);
}
void query(int l,int r,int o,int ll,int rr){
if(l>=ll&&r<=rr){
ha+=sm[o];ma=max(ma,s2[o]);
return;
}
int mid=(l+r)>>1;
if(mid>=ll)query(l,mid,o<<1,ll,rr);
if(mid<rr)query(mid+1,r,o<<1|1,ll,rr);
}
int main(){
int ca;
scanf("%d",&ca);
int n;
scanf("%d",&n);
int my=INT_MAX,mx=INT_MAX,wz=0;
for(int i=1;i<=n;++i){
scanf("%d%d",&x[i],&y[i]);
scanf("%d",&d[i]);
if(my>y[i]||(my==y[i]&&mx>x[i]))my=y[i],mx=x[i],wz=i;
}
int q;
scanf("%d",&q);
for(int i=1;i<=q;++i){
char oo[15];
scanf("%s",oo+1);
if(oo[1]=='H'){
op[i]=1;
scanf("%d%d",&xx[i],&dd[i]);
}else{
op[i]=2;
scanf("%d",&m[i]);
gg[i].resize(m[i]);
for(int j=0;j<m[i];++j){
scanf("%d",&gg[i][j]);
}
for(int j=0;j<m[i];++j){
int u=gg[i][j],v=gg[i][(j+1)%m[i]];
g[u].emplace_back(v);
g[v].emplace_back(u);
}
}
}
dfs0(wz,0);
for(int i=1;i<=n;++i)if(i!=wz){
g2[fa[i]].emplace_back(getpi(x[i]-x[fa[i]],y[i]-y[fa[i]]),i);
}
for(int i=1;i<=n;++i){
sort(g2[i].begin(),g2[i].end());
}
dfs1(wz);
for(int i=1;i<=n;++i)a[bg[i]]=d[i];
build(1,n,1);
for(int i=1;i<=q;++i){
if(op[i]==1){
a[bg[xx[i]]]+=dd[i];
gai(1,n,1,bg[xx[i]]);
}else{
ha=0,ma=0;
int k=m[i];tt=0;
reverse(gg[i].begin(),gg[i].end());
for(int j=0;j<k;++j){
int u=gg[i][j],v=gg[i][(j+1)%k],w=gg[i][(j+2)%k];
ha+=a[bg[v]];ma=max(ma,a[bg[v]]);
fenshu L=getpi(x[u]-x[v],y[u]-y[v]),R=getpi(x[w]-x[v],y[w]-y[v]);
int xl=lower_bound(g2[v].begin(),g2[v].end(),make_pair(L,0))-g2[v].begin();
int xr=lower_bound(g2[v].begin(),g2[v].end(),make_pair(R,n+1))-g2[v].begin()-1;
if(!(R<L)){
if(xl<=xr){
jia(bg[g2[v][xl].second],en[g2[v][xr].second],1);
}
if(fa[v]){
fenshu ff=getpi(x[fa[v]]-x[v],y[fa[v]]-y[v]);
if(ff<L||R<ff);
else{
jia(bg[v],en[v],-1);
}
}
}else{
if(xl<(signed)g2[v].size()){
jia(bg[g2[v][xl].second],en[g2[v][g2[v].size()-1].second],1);
}
if(xr>=0){
jia(bg[g2[v][0].second],en[g2[v][xr].second],1);
}
if(fa[v]){
fenshu ff=getpi(x[fa[v]]-x[v],y[fa[v]]-y[v]);
if(ff<L&&R<ff);
else{
jia(bg[v],en[v],-1);
}
}
}
}
sort(pi+1,pi+tt+1);
for(int j=2;j<=tt;j+=2){
int L=pi[j-1],R=pi[j]-1;
if(L<=R)query(1,n,1,L,R);
}
printf("%lld %lld\n",ha,ma);
}
}
return 0;
}

浙公网安备 33010602011771号