[二进制分组 线段树 || 点分治 分治] UOJ #191 【集训队互测2016】Unknown

608人阅读 评论(1) 收藏 举报
分类:

详见lzz的集训队论文

二进制分组做法

二进制分组是在线段树的结构上做的 方便区间查询
至于删除 采用延迟重构的思想 每一层只有最后一个区间是萎的 我们需要递归下去 询问还是O(logn)个节点 重构复杂度势能分析下O(nlogn)
只有上凸包是有效的 合并的时候采用归并加Graham可以做到O(n) 不然以我的常数 T的血惨
但是卡内存 只有90分

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<vector>
#include<cmath>
#include<cassert>
#define pb push_back
using namespace std;
typedef double ld;
typedef long long ll;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
  char c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int N=550005;
const ld PI=acos(-1.0);

struct PP{
  ll x,y;
  PP(ll x=0,ll y=0):x(x),y(y) { }
  friend PP operator + (PP A,PP B){ return PP(A.x+B.x,A.y+B.y); }
  friend PP operator - (PP A,PP B){ return PP(A.x-B.x,A.y-B.y); }
  friend ll operator * (PP A,PP B){ return A.x*B.y-A.y*B.x; }
  friend ld Ang(PP A,PP B){
    ld ang=atan2(B.y-A.y,B.x-A.x);
    return (B.y<A.y&&B.x<=A.x)?ang+2*PI:ang;
  }
  bool operator < (const PP &B) const{
    return x==B.x?y<B.y:x<B.x;
  }
};

vector<int> hull[N<<1];

int tmp[N]; int cnt,pnt;

PP pp[N];

int ncnt;
int last[N];
int ls[N<<1],rs[N<<1],lp[N<<1],lb[N<<1],rb[N<<1];
int tag[N<<1];

inline void BH(int x,int l,int r){
  hull[x].clear();
  if (l==r) { hull[x].pb(l); return; }
  int p=0,q=0; cnt=0;
  //assert(tag[ls[x]] && tag[rs[x]]);
  for (;p<hull[ls[x]].size() || q<hull[rs[x]].size();){
    int t;
    if (p==hull[ls[x]].size())
      t=hull[rs[x]][q++];
    else if (q==hull[rs[x]].size())
      t=hull[ls[x]][p++];
    else if (pp[hull[ls[x]][p]].x<pp[hull[rs[x]][q]].x)
      t=hull[ls[x]][p++];
    else
      t=hull[rs[x]][q++];
    if (cnt && pp[t].x==pp[tmp[cnt]].x){
      if (pp[tmp[cnt]].y<pp[t].y) tmp[cnt]=t;
    }else
      tmp[++cnt]=t;
  }
  pnt=0;
  for (int i=1;i<=cnt;i++){
    while (pnt>=2 && (pp[tmp[i]]-pp[tmp[pnt]])*(pp[tmp[pnt]]-pp[tmp[pnt-1]])<=0) pnt--;
    tmp[++pnt]=tmp[i];
  }
  for (int i=1;i<=pnt;i++)
    hull[x].pb(tmp[i]);
}
inline ll query(int x,PP p){
  int L=-1,R=hull[x].size()-1,MID;
  while (L+1<R){
    MID=(L+R)>>1;
    if ((pp[hull[x][MID+1]]-pp[hull[x][MID]])*p<=0)
      L=MID;
    else
      R=MID;
  }
  return p*pp[hull[x][R]];
}


inline void Build(int &x,int l,int r,int d=0){
  x=++ncnt; lp[x]=last[d]; last[d]=x; lb[x]=l; rb[x]=r;
  if (l==r) return;
  int mid=(l+r)>>1;
  Build(ls[x],l,mid,d+1); Build(rs[x],mid+1,r,d+1);
}

inline void Add(int x,int l,int r,int t){
  if (t==r && lp[x]) tag[lp[x]]=1,BH(lp[x],lb[lp[x]],rb[lp[x]]);
  if (l==r) return;
  int mid=(l+r)>>1;
  if (t<=mid) Add(ls[x],l,mid,t);
  else Add(rs[x],mid+1,r,t);
}
inline void Del(int x,int l,int r,int t){
  tag[x]=0;
  if (l==r) return;
  int mid=(l+r)>>1;
  if (t<=mid) Del(ls[x],l,mid,t);
  else Del(rs[x],mid+1,r,t);
}

ll Ret;
inline void Query(int x,int l,int r,int ql,int qr,PP p){
  if (ql<=l && r<=qr && (tag[x] || l==r)){
    if (l<r)
      Ret=max(Ret,query(x,p));
    else
      Ret=max(Ret,p*pp[l]);
    return;
  }
  int mid=(l+r)>>1;
  if (ql<=mid) Query(ls[x],l,mid,ql,qr,p);
  if (qr>mid) Query(rs[x],mid+1,r,ql,qr,p);
}

const int P=998244353;

int main(){
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  int order,x,y,l,r;
  int m; read(m);
  while (1){
    read(m); if (m==0) break;
    int tot=0,rt; int n=1; while (n<m) n<<=1;
    ncnt=0;
    Build(rt,1,n);
    int ans=0;
    while (m--){
      read(order); 
      if (order==1)
    read(x),read(y),pp[++tot]=PP(x,y),Add(1,1,n,tot);
      else if (order==2)
    Del(1,1,n,tot--);
      else{
    Ret=-1LL<<60; read(l); read(r); read(x); read(y);
    Query(1,1,n,l,r,PP(x,y));
    ans^=((Ret%P)+P)%P;
      }
    }
    printf("%d\n",ans);
    for (int i=1;i<=ncnt;i++) ls[i]=rs[i]=lp[i]=last[i]=tag[i]=0,hull[i].clear();
  }
  return 0;
}

操作树上点分治

发现加入删除就类似dfs中栈的过程 这样我们把操作树建出来就转化为一条方向到根的路径 点分后统计下重心到根的贡献更新下 这个再用一个分治就好了 具体最优能做到几个log 看论文 不然可能还是T的血惨
还是卡内存 好不容易卡进了 被cha了 只有97

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<vector>
#define pb push_back
using namespace std;
//typedef pair<int,int> abcd;
#define abcd PP
#define first x
#define second y
typedef double ld;
typedef long long ll;

inline char nc(){
  static char buf[100000],*p1=buf,*p2=buf;
  return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
  char c=nc(),b=1;
  for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;
  for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;
}

const int N=300005;
const ld PI=acos(-1.0);

struct PP{
  ll x,y;
  PP(ll x=0,ll y=0):x(x),y(y) { }
  friend PP operator + (PP A,PP B){ return PP(A.x+B.x,A.y+B.y); }
  friend PP operator - (PP A,PP B){ return PP(A.x-B.x,A.y-B.y); }
  friend ll operator * (PP A,PP B){ return A.x*B.y-A.y*B.x; }
  bool operator < (const PP &B) const{
    return x==B.x?y<B.y:x<B.x;
  }
};

struct edge{
  int v,next;
}G[N<<1];
int head[N],qhead[N],inum;
inline void add(int u,int v,int p,int *head=::head){
  /*G[p].u=u;*/ G[p].v=v; G[p].next=head[u]; head[u]=p;
}
#define V G[p].v
int ncnt; //int Stack[N],Pnt;
PP pp[N];

int fat[N],depth[N];

bool del[N];

int minv=1<<30,size[N],sum,rt;
inline void Root(int u,int fa){
  size[u]=1; int maxv=0;
  for (int p=head[u];p;p=G[p].next)
    if (V!=fa && !del[V])
      Root(V,u),size[u]+=size[V],maxv=max(maxv,size[V]);
  maxv=max(maxv,sum-size[u]);
  if (minv>maxv) minv=maxv,rt=u;
}

//vector<int> que[N];
int tot,uu[N]/*,vv[N]*/; ll ans[N];
PP qp[N];

bool cmp(abcd x,abcd y){
  return qp[x.second]*qp[y.second]<=0;
}

PP po[N]; int pcnt; PP tmpp[N];
abcd qq[N]; int qcnt; //abcd tmp[N];

inline void divide(int l,int r,int ql,int qr,int &hcnt){
  if (l==r){
    sort(qq+ql,qq+qr+1,cmp);
    for (int i=ql;i<=qr;i++)
      ans[qq[i].second]=max(ans[qq[i].second],qp[qq[i].second]*po[l]);
    hcnt=1;
    return;
  }
  int lh=0,rh=0; int mid=(l+r)>>1;
  int lp=ql-1,rp=qr+1;
  for (int i=ql;i<=qr;i++)
    if (qq[i].first<=mid) tmpp[++lp]=qq[i]; else tmpp[--rp]=qq[i];
  for (int i=ql;i<=qr;i++) qq[i]=tmpp[i];

  divide(l,mid,ql,lp,lh);
  divide(mid+1,r,rp,qr,rh);

  int j=1;
  for (int i=rp;i<=qr;i++){
    while (j+1<=lh && qp[qq[i].second]*po[l+j-1]<qp[qq[i].second]*po[l+(j+1)-1])
      j++;
    ans[qq[i].second]=max(ans[qq[i].second],qp[qq[i].second]*po[l+j-1]);
  }

  if (!(l==1 && r==pcnt)){
    int p=1,q=1; int cnt=0;
    while (p<=lh || q<=rh){
      PP t;
      if (p==lh+1 || (q<=rh && po[mid+q].x<=po[l+p-1].x))
    t=po[mid+(q++)];
      else
    t=po[l+(p++)-1];
      if (!cnt || tmpp[cnt].x!=t.x)
    tmpp[++cnt]=t;
      else
    tmpp[cnt].y=max(tmpp[cnt].y,t.y);
    }
    int pnt=0;
    for (int i=1;i<=cnt;i++){
      while (pnt>=2 && (tmpp[i]-tmpp[pnt])*(tmpp[pnt]-tmpp[pnt-1])<=0) pnt--;
      tmpp[++pnt]=tmpp[i];
    }
    hcnt=pnt;
    for (int i=1;i<=pnt;i++) po[l+i-1]=tmpp[i];

    pnt=0,p=ql,q=rp;
    while (p<=lp || q<=qr){
      if (p==lp+1 || (q<=qr && qp[qq[q].second]*qp[qq[p].second]<0))
    tmpp[++pnt]=qq[q++];
      else
    tmpp[++pnt]=qq[p++];
    }
    for (int i=1;i<=pnt;i++) qq[ql+i-1]=tmpp[i];
  }
}

int R,Gg;

inline void dfs(int u,int fa){
  //for (int i:que[u])
  for (int p=qhead[u];p;p=G[p].next){
    int i=V;
    if (depth[uu[i]]<=depth[Gg])
      qq[++qcnt]=abcd(depth[Gg]-max(depth[uu[i]],depth[R])+1,i);
  }
  for (int p=head[u];p;p=G[p].next)
    if (V!=fa && !del[V])
      dfs(V,u);
}

inline void Divide(int u,int S){
  sum=S; minv=1<<30; Root(u,0);
  R=u; Gg=rt;
  pcnt=0; int t=Gg; while (t!=R) po[++pcnt]=pp[t],t=fat[t]; po[++pcnt]=pp[R];
  qcnt=0; dfs(Gg,fat[Gg]);
  int tmp; if (qcnt) divide(1,pcnt,1,qcnt,tmp);

  int tt=Gg;
  del[Gg]=1;
  if (Gg^R) Divide(u,S-size[Gg]);
  for (int p=head[tt];p;p=G[p].next)
    if (!del[V])
      Divide(V,size[V]);
}

const int P=998244353;

int main(){
  freopen("t.in","r",stdin);
  freopen("t.out","w",stdout);
  int m; int order,l,r,x,y;
  read(m);
  while (1){
    read(m); if (!m) break; int cur=0,Pnt=0,*Stack=size;tot=ncnt=0;
    Stack[++Pnt]=++ncnt; cur=ncnt;
    while (m--){
      read(order);
      if (order==1){
    ++ncnt; if (cur) add(cur,ncnt,++inum),fat[ncnt]=cur;
    depth[ncnt]=depth[fat[ncnt]]+1;
    cur=ncnt; Stack[++Pnt]=ncnt;
    read(x); read(y); pp[ncnt]=PP(x,y);
      }else if (order==2){
    cur=fat[cur]; Stack[Pnt--]=0;
      }else if (order==3){
    read(l); read(r); read(x); read(y);
    ++tot; ans[tot]=-1LL<<60; qp[tot]=PP(x,y);  uu[tot]=Stack[l+1];
    //vv[tot]=Stack[r+1]; que[vv[tot]].pb(tot);
    //que[Stack[r+1]].pb(tot);
    add(Stack[r+1],tot,++inum,qhead);
      }
    }
    Divide(1,ncnt);
    int Ans=0;
    for (int i=1;i<=tot;i++)
      Ans^=(ans[i]%P+P)%P;
    printf("%d\n",Ans);
    for (int i=1;i<=ncnt;i++) head[i]=del[i]=fat[i]=depth[i]=0,qhead[i]=0/*,que[i].clear()*/; inum=0;
  }
  return 0;
}
查看评论

bzoj2989&4170【二进制分组】【主席树】

其实没有要求强制在线,可以直接上CDQ分治 二进制分组嘛可以看看2013年xhr的《浅谈数据结构题的几个非经典解法》 或者看看%%CA的博客http://m.blog.csdn.net/artic...
  • stony_oi
  • stony_oi
  • 2016-12-16 15:29:42
  • 670

BZOJ 4140: 共点圆加强版 [二进制分组][凸包]

题意 支持在平面直角坐标系内进行操作: 1.加入一个圆心在(x,y)(x,y)且过原点的圆 2.询问点(x,y)(x,y)是否被之前加入的所有圆包含(在圆内或圆心上) 强制在线 题解 ...
  • qq_35878547
  • qq_35878547
  • 2018-01-11 10:00:39
  • 81

DWR Annotation入门示例

DWR(Direct Web Remoting)是一个用于改善web页面与Java类交互的远程服务器端Ajax开源框架,可以帮助开发人员开发包含AJAX技术的网站.它可以允许在浏览器里的代码使用运行在...
  • kuangxiang_panpan
  • kuangxiang_panpan
  • 2012-03-28 15:59:06
  • 1909

[二进制分组维护凸包]BZOJ 4140—— 共点圆加强版

[二进制分组维护凸包]BZOJ 4140—— 共点圆加强版题目描述在平面直角坐标系中,Wayne需要你完成n次操作,操作只有两种:1.0 x y。表示在坐标系中加入一个以(x, y)为圆心且过原点的圆...
  • CHN_JZ
  • CHN_JZ
  • 2017-12-28 18:10:53
  • 359

[阈值 二进制分组 && AC自动机]HDU4787. GRE Words Revenge

如果不强制在线,那么可以分治,所以想到可以二进制分组。 但是询问总长度是 5×1065\times 10^6,乘个log看着虚…可以只建两个AC自动机,当其中一个AC自动机的节点数超过某个值的时候,...
  • Coldef
  • Coldef
  • 2017-09-25 16:42:44
  • 174

[二进制构造 || DP] BZOJ 3107 [cqoi2013]二进制a+b

可以类似数位DP 然后Po姐 的构造好劲啊 Orz http://blog.csdn.net/popoqqq/article/details/48006557 #include #i...
  • u014609452
  • u014609452
  • 2016-05-20 16:36:48
  • 273

【从此不怕强制在线】二进制分组学习笔记

总是遇到分治被强制在线卡真是令人不爽>_< 那我们就用二进制分组大法来破掉他的强制在线! 二进制分组大法是什么咧= = (学习自许昊然《浅谈数据结构题的几个非经典解法》) 我们把一个数拆成2的...
  • CreationAugust
  • CreationAugust
  • 2015-08-24 19:43:28
  • 3166

jQuery EasyUI API 中文文档 - DataGrid数据表格

扩展自 $.fn.panel.defaults ,用 $.fn.datagrid.defaults 重写了 defaults 。 依赖 panel resizable linkbutt...
  • dqsweet
  • dqsweet
  • 2012-03-26 14:11:00
  • 2221

[分块] BZOJ 2122 工作评估

比较好的一道分块题 重要结论F(i,j,x0)=min( G(i,j), x0+S(i,j)) 详见:http://blog.csdn.net/u011542204/article/details...
  • u014609452
  • u014609452
  • 2016-09-23 17:11:46
  • 520

【UOJ 191/集训队互测】Unknown

【UOJ 191/集训队互测】Unknown题意\quad有一个初始为空的栈和m(m
  • Jazengm
  • Jazengm
  • 2017-10-26 17:32:30
  • 449
    个人资料
    持之以恒
    等级:
    访问量: 40万+
    积分: 1万+
    排名: 1233
    文章分类
    最新评论