BZOJ3592 : Architext

Claris發表於2019-02-20

首先特判多邊形面積$=0$的情況,此時內部沒有點,答案只會在頂點處取到。

對於面積$>0$的情況,離線詢問,將所有多邊形合在一起得到平面圖,然後求出對偶圖,那麼每條多邊形邊的兩側分別對應對偶圖中兩個域。

每個多邊形把這些域分成內外兩個連通塊,也就是保留除了多邊形邊之外的所有邊後對偶圖的連通情況。

把每個點隨便放在所在的某個域之中,按時間分治,維護按秩合併的並查集。

對於每個詢問任取一條多邊形邊,它兩側分別是域$A$和域$B$。那麼有且僅有一個不與無窮域連通,假設是$A$,那麼答案就是$A$所在連通塊的資訊。這會漏掉一些因為隨便指派而不在連通塊內的頂點。遍歷每個頂點$x$,判斷$x$所在域所在連通塊是否和無窮域連通,是的話再把$x$的資訊加入答案即可。

時間複雜度$O(n\log^2n)$。

 

#include<cstdio>
#include<cmath>
#include<set>
#include<algorithm>
#include<map>
#include<vector>
using namespace std;
typedef pair<int,int>PI;
typedef long long ll;
const int N=50010,M=320010;
int Case,n,m,cq,cnt,i,j,k,x,y,z,q[N],at[N];
map<PI,int>idx;
int que[N][3];
vector<int>pool[N];
int dep[M],f[M],sum[M],mx[M],val[N];
int laste[M],lastv[N];
int co,op[N*3+M*2][3];
int MX,SUM;
struct EV{
  char op;int x,y,l,r;
  EV(){}
  EV(char _op,int _x,int _y,int _l,int _r){op=_op,x=_x,y=_y,l=_l,r=_r;}
};
typedef vector<EV>V;
struct P{
  int x,y,d;
  ll operator*(const P&b){return 1LL*x*b.y-1LL*y*b.x;}
}a[N];
struct E{
  int x,y;double o;
  E(){}
  E(int _x,int _y){x=_x,y=_y,o=atan2(a[y].x-a[x].x,a[y].y-a[x].y);}
}e[M];
bool del[M];int from[M];
namespace GetArea{
struct cmp{bool operator()(int a,int b){return e[a].o<e[b].o;}};
set<int,cmp>g[N];set<int,cmp>::iterator k;int i,j,q[M],t;
void work(){
  for(i=0;i<m+m;i++)if(!del[i]){
    for(q[t=1]=j=i;;q[++t]=j=*k){
      k=g[e[j].y].find(j^1);k++;
      if(k==g[e[j].y].end())k=g[e[j].y].begin();
      if(*k==i)break;
    }
    ll s=0;
    for(j=1;j<=t;j++)s+=a[e[q[j]].x]*a[e[q[j]].y],del[q[j]]=1;
    if(s<=0)continue;
    for(cnt++,j=1;j<=t;j++){
      from[q[j]]=cnt;
      at[e[q[j]].x]=at[e[q[j]].y]=cnt;
    }
  }
}
}
inline void newedge(int x,int y){
  if(idx.find(PI(x,y))!=idx.end())return;
  if(idx.find(PI(y,x))!=idx.end())return;
  e[m<<1]=E(x,y);
  e[m<<1|1]=E(y,x);
  idx[PI(x,y)]=idx[PI(y,x)]=m++;
}
inline int getid(int x,int y){return idx[PI(x,y)];}
int F(int x){return f[x]==x?x:F(f[x]);}
inline void merge(int x,int y){
  x=F(x),y=F(y);
  if(x==y)return;
  if(dep[x]==dep[y]){
    co++;
    op[co][0]='d';
    op[co][1]=x;
    dep[x]++;
  }
  if(dep[x]<dep[y])swap(x,y);
  co++;
  op[co][0]='f';
  op[co][1]=y;
  f[y]=x;
  if(mx[y]>mx[x]){
    co++;
    op[co][0]='m';
    op[co][1]=x;
    op[co][2]=mx[x];
    mx[x]=mx[y];
  }
  co++;
  op[co][0]='s';
  op[co][1]=x;
  op[co][2]=sum[y];
  sum[x]+=sum[y];
}
inline void ins(int x,int y){
  int z=F(at[x]);
  co++;
  op[co][0]='v';
  op[co][1]=x;
  op[co][2]=val[x];
  val[x]=y;
  if(y>mx[z]){
    co++;
    op[co][0]='m';
    op[co][1]=z;
    op[co][2]=mx[z];
    mx[z]=y;
  }
  co++;
  op[co][0]='s';
  op[co][1]=z;
  op[co][2]=y;
  sum[z]+=y;
}
inline void retrace(int t){
  while(co>t){
    if(op[co][0]=='d')dep[op[co][1]]--;
    else if(op[co][0]=='f')f[op[co][1]]=op[co][1];
    else if(op[co][0]=='v')val[op[co][1]]=op[co][2];
    else if(op[co][0]=='m')mx[op[co][1]]=op[co][2];
    else sum[op[co][1]]-=op[co][2];
    co--;
  }
}
inline void up(int&a,int b){a<b?(a=b):0;}
void solve(int l,int r,V v){
  int pos=co,mid=(l+r)>>1;
  V vl,vr;
  for(V::iterator it=v.begin();it!=v.end();it++){
    if(it->l<=l&&r<=it->r){
      if(it->op=='E')merge(it->x,it->y);
      else ins(it->x,it->y);
    }else{
      if(it->l<=mid)vl.push_back(*it);
      if(it->r>mid)vr.push_back(*it);
    }
  }
  if(l==r){
    if(que[l][0]==1){
      int j,o,u,k=que[l][1];
      for(j=0;j<k;j++)q[j]=pool[l][j];
      q[k]=q[0];
      MX=SUM=0;
      if(que[l][2]){
        for(j=0;j<k;j++){
          o=q[j];
          SUM+=val[o];
          up(MX,val[o]);
        }
      }else{
        o=getid(q[0],q[1])<<1;
        u=from[o];
        if(F(u)==F(0))u=from[o|1];
        u=F(u);
        SUM=sum[u];
        MX=mx[u];
        for(j=0;j<k;j++){
          o=q[j];
          if(F(at[o])!=u){
            SUM+=val[o];
            up(MX,val[o]);
          }
        }
      }
      printf("%d %d\n",SUM,MX);
    }
    retrace(pos);
    return;
  }
  solve(l,mid,vl);
  solve(mid+1,r,vr);
  retrace(pos);
}
int main(){
  scanf("%d%d",&Case,&n);
  for(i=1;i<=n;i++)scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].d);
  scanf("%d",&cq);
  if(!cq)return 0;
  for(i=1;i<=cq;i++){
    char op[5];
    scanf("%s",op);
    if(op[0]=='H')scanf("%d%d",&que[i][1],&que[i][2]);
    else{
      que[i][0]=1;
      scanf("%d",&k);
      que[i][1]=k;
      for(j=0;j<k;j++)scanf("%d",&q[j]);
      q[k]=q[0];
      for(j=0;j<k;j++)newedge(q[j],q[j+1]);
      pool[i].resize(k);
      for(j=0;j<k;j++)pool[i][j]=q[j];
    }
  }
  for(i=0;i<m+m;i++)GetArea::g[e[i].x].insert(i);
  GetArea::work();
  V v;
  for(i=1;i<=n;i++)lastv[i]=1;
  for(i=1;i<=cq;i++){
    if(que[i][0]==0){
      x=que[i][1];
      y=lastv[x];
      if(y<=i-1)v.push_back(EV('V',x,a[x].d,y,i-1));
      a[x].d+=que[i][2];
      lastv[x]=i;
    }else{
      k=que[i][1];
      for(j=0;j<k;j++)q[j]=pool[i][j];
      q[k]=q[0];
      ll s=0;
      for(j=0;j<k;j++)s+=a[q[j]]*a[q[j+1]];
      if(s<0){
        for(j=0;j<k;j++){
          x=getid(q[j],q[j+1]);
          y=laste[x];
          if(y+1<=i-1)v.push_back(EV('E',from[x<<1],from[x<<1|1],y+1,i-1));
          laste[x]=i;
        }
      }else que[i][2]=1;
    }
  }
  for(i=1;i<=n;i++)v.push_back(EV('V',i,a[i].d,lastv[i],cq));
  for(i=0;i<=cnt;i++)f[i]=i;
  for(i=0;i<m;i++){
    y=laste[i];
    if(y+1<=cq)v.push_back(EV('E',from[i<<1],from[i<<1|1],y+1,cq));
  }
  solve(1,cq,v);
  return 0;
}