[二进制分组 线段树 || 点分治 分治] UOJ #191 【集训队互测2016】Unknown
来源:互联网 发布:先导爱知在g出现吗 编辑:程序博客网 时间:2024/06/06 09:33
详见lzz的集训队论文
二进制分组做法
二进制分组是在线段树的结构上做的 方便区间查询
至于删除 采用延迟重构的思想 每一层只有最后一个区间是萎的 我们需要递归下去 询问还是
只有上凸包是有效的 合并的时候采用归并加Graham可以做到
但是卡内存 只有90分
#include<cstdio>#include<cstdlib>#include<algorithm>#include<vector>#include<cmath>#include<cassert>#define pb push_backusing 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_backusing namespace std;//typedef pair<int,int> abcd;#define abcd PP#define first x#define second ytypedef 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].vint 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;}
阅读全文
0 0
- [二进制分组 线段树 || 点分治 分治] UOJ #191 【集训队互测2016】Unknown
- 【UOJ 191/集训队互测】Unknown
- [UOJ191][集训队互测2016]Unknown-线段树-斜率优化
- 树分治-点分治
- 树分治(点分治+边分治)
- 树的分治-点分治
- Uoj 33 树上GCD (树分治)
- LA3938 线段树+分治
- 树的点分治
- 树的点分治
- bzoj2006 [ NOI2010 ] && bzoj3784 --点分治+线段树+堆
- 【jzoj4715】【树上路径】【树】【分治】【点分治】
- POJ1741树的分治之点分治
- UOJ 88 [集训队互测2015]Robot
- 点分治
- 点分治
- 点分治
- 点分治
- POJ3681-Finding the Rectangle
- 字符串函数记录
- Tomcat+JSP+Oracle信息查询系统开发笔记(1)
- 使用Windriver生成CPCI驱动步骤
- Cookie和Web缓存机制
- [二进制分组 线段树 || 点分治 分治] UOJ #191 【集训队互测2016】Unknown
- MyBatis分页插件PageHelper
- 【简记】大规模Web开发技术(第九章)
- 一起读论文
- UESTC 1636 梦后楼台高锁,酒醒帘幕低垂 最小生成树Kruskal算法的扩展
- java 文件夹的创建 删去 和 重命名
- socket编程---服务器端与客户端简单通信
- 【高效程序员系列】2、别做机器人------让工作自动化
- 二叉树的下一个结点