[UOJ55]紫荆花之恋
第一次打“真正的”动态点分
如果树是静态的,直接点分:用$d_x$代表$x$到分治中心的距离,限制条件即为$d_i+d_j\leq r_i+r_j$,考虑枚举$j$,那么我们要查询有多少满足$d_i-r_i\leq r_j-d_j$的$i$,用平衡树维护即可
现在树是动态的,那么每次我们往点分树中加一个叶子,先更新答案再更新平衡树即可,每个点分树中的点存两棵平衡树,一棵存以这个点为dfs起点的$d_i-r_i$,另一棵存以(它父亲到它管辖范围的第一个点)为dfs起点的$d_i-r_i$,查询时容斥一下就可以了
但直接加叶子会造成点分树不平衡,所以这里用替罪羊树的思想重构,这样就能保证时间复杂度
实现起来还是需要一点技巧的,如果要重构点分树中的一个点$x$,那么在原树中dfs时只访问那些在点分树中比$x$深的点就对应着$x$的点分树子树了,平衡树使用旋转treap,重构时先内存回收,再排序后$O(n)$建treap,这样会快一些(好吧主要是我写的常数太大...)
#include<stdio.h> #include<stdlib.h> #include<algorithm> #include<assert.h> using namespace std; typedef long long ll; const int inf=2147483647; ll ans; int r[100010],*d,*r1,*r2,*sz,*df; namespace tree{ int h[100010],nex[200010],to[200010],v[200010],M; void ins(int a,int b,int c){ M++; to[M]=b; v[M]=c; nex[M]=h[a]; h[a]=M; } int fa[100010][17],dep[100010],dis[100010]; void add(int a,int b,int c){ ins(a,b,c); ins(b,a,c); fa[b][0]=a; dep[b]=dep[a]+1; dis[b]=dis[a]+c; for(int i=1;i<17;i++)fa[b][i]=fa[fa[b][i-1]][i-1]; } int lca(int x,int y){ int i; if(dep[x]<dep[y])swap(x,y); for(i=16;i>=0;i--){ if(dep[fa[x][i]]>=dep[y])x=fa[x][i]; } if(x==y)return x; for(i=16;i>=0;i--){ if(fa[x][i]!=fa[y][i]){ x=fa[x][i]; y=fa[y][i]; } } return fa[x][0]; } int vis[100010],siz[100010],lim,C; #define ok vis[to[i]]!=C&&to[i]!=fa&&d[to[i]]>=lim void dfs1(int fa,int x){ siz[x]=1; for(int i=h[x];i;i=nex[i]){ if(ok){ dfs1(x,to[i]); siz[x]+=siz[to[i]]; } } } int mn,cn,n; void dfs2(int fa,int x){ int i,k=0; for(i=h[x];i;i=nex[i]){ if(ok){ dfs2(x,to[i]); k=max(k,siz[to[i]]); } } k=max(k,n-siz[x]); if(k<mn){ mn=k; cn=x; } } } int getdis(int x,int y){ using namespace tree; return dis[x]+dis[y]-dis[lca(x,y)]*2; } namespace treap{ int fa[4000010],ch[4000010][2],fix[4000010],s[4000010],v[4000010],st[4000010],tp,M; #define l(x) ch[x][0] #define r(x) ch[x][1] int node(int d){ int x; if(tp){ x=st[tp--]; fa[x]=l(x)=r(x)=0; }else x=++M; fix[x]=rand(); v[x]=d; s[x]=1; return x; } void pushup(int x){ s[x]=s[l(x)]+s[r(x)]+1; } void rot(int x){ int y,z,f,b; y=fa[x]; z=fa[y]; f=ch[y][0]==x; b=ch[x][f]; fa[x]=z; fa[y]=x; if(b)fa[b]=y; ch[x][f]=y; ch[y][f^1]=b; if(ch[z][0]==y)ch[z][0]=x; if(ch[z][1]==y)ch[z][1]=x; pushup(y); pushup(x); } int insert(int&x,int d){ if(x==0)return x=node(d); int k; if(d<=v[x]){ k=insert(l(x),d); if(!fa[l(x)])fa[l(x)]=x; }else{ k=insert(r(x),d); if(!fa[r(x)])fa[r(x)]=x; } pushup(x); return k; } void ins(int&x,int d){ int k=insert(x,d); while(fa[k]&&fix[k]>fix[fa[k]])rot(k); while(fa[x])x=fa[x]; } int query(int x,int d){ if(x==0)return 0; if(d>=v[x])return s[l(x)]+1+query(r(x),d); return query(l(x),d); } void rec(int x){ if(!x)return; st[++tp]=x; rec(l(x)); rec(r(x)); } int stk[100010],top; int build(int*p,int n){ int x,las,i; sort(p+1,p+n+1); top=0; for(i=1;i<=n;i++){ x=node(p[i]); las=0; while(top&&fix[stk[top]]<fix[x]){ pushup(stk[top]); las=stk[top--]; } if(top)r(stk[top])=x; l(x)=las; stk[++top]=x; } while(top)pushup(stk[top--]); return stk[1]; } } void drec(int fa,int x){ using namespace tree; using namespace treap; rec(r1[x]); r1[x]=0; rec(r2[x]); r2[x]=0; for(int i=h[x];i;i=nex[i]){ if(to[i]!=fa&&d[to[i]]>=lim)drec(x,to[i]); } } int p[100010],N,u; void dfs3(int fa,int x){ using namespace tree; p[++N]=getdis(x,u)-r[x]; for(int i=h[x];i;i=nex[i]){ if(ok)dfs3(x,to[i]); } } int solve(int fa,int x){ using namespace tree; dfs1(0,x); mn=inf; n=siz[x]; dfs2(0,x); if(fa){ u=fa; N=0; dfs3(0,x); r2[cn]=treap::build(p,N); } x=cn; vis[x]=C; df[x]=fa; d[x]=d[fa]+1; u=x; N=0; dfs3(0,x); r1[x]=treap::build(p,N); sz[x]=1; for(int i=h[x];i;i=nex[i]){ if(ok)sz[x]+=sz[solve(x,to[i])]; } return x; } void rebuild(int fa,int x){ using namespace tree; lim=d[x]; drec(0,x); C++; solve(fa,x); } namespace dtree{ const double al=.85; int fa[100010],rt1[100010],rt2[100010],siz[100010],dep[100010]; //rt1:root=self,rt2:root=fa->self_area_1st void addnode(int x){ fa[x]=tree::fa[x][0]; dep[x]=dep[fa[x]]+1; int u,t; for(u=x;fa[u];u=fa[u]){ t=getdis(x,fa[u]); ans+=treap::query(rt1[fa[u]],r[x]-t); ans-=treap::query(rt2[u],r[x]-t); } treap::ins(rt1[x],-r[x]); for(u=x;fa[u];u=fa[u]){ t=getdis(x,fa[u]); treap::ins(rt1[fa[u]],t-r[x]); treap::ins(rt2[u],t-r[x]); } for(u=x;u;u=fa[u])siz[u]++; t=0; for(u=x;fa[u];u=fa[u]){ if(siz[u]>al*siz[fa[u]])t=fa[u]; } if(t)rebuild(fa[t],t); } } int main(){ using namespace treap; using namespace dtree; srand(19260817); int n,i,a,c; d=dep; r1=rt1; r2=rt2; sz=siz; df=dtree::fa; scanf("%d%d",&a,&n); scanf("%d%d%d",&a,&c,r+1); ins(rt1[1],-r[1]); d[1]=1; sz[1]=1; puts("0"); for(i=2;i<=n;i++){ scanf("%d%d%d",&a,&c,r+i); a^=(ans%1000000000); tree::add(a,i,c); addnode(i); printf("%lld\n",ans); } }
[UOJ55]紫荆花之恋的更多相关文章
- bzoj 3435: [Wc2014]紫荆花之恋 替罪羊树维护点分治 && AC400
3435: [Wc2014]紫荆花之恋 Time Limit: 240 Sec Memory Limit: 512 MBSubmit: 159 Solved: 40[Submit][Status] ...
- 【BZOJ3435】[Wc2014]紫荆花之恋 替罪点分树+SBT
[BZOJ3435][Wc2014]紫荆花之恋 Description 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从 ...
- BZOJ 3435: [Wc2014]紫荆花之恋
二次联通门 : BZOJ 3435: [Wc2014]紫荆花之恋 二次联通门 : luogu P3920 [WC2014]紫荆花之恋 /* luogu P3920 [WC2014]紫荆花之恋 怀疑人生 ...
- luogu P3920 [WC2014]紫荆花之恋
LINK:紫荆花之恋 每次动态加入一个节点 统计 有多少个节点和当前节点的距离小于他们的权值和. 显然我们不能n^2暴力. 考虑一个简化版的问题 树已经给出 每次求某个节点和其他节点的贡献. 不难想到 ...
- 【WC2014】紫荆花之恋(替罪羊重构点分树 & 平衡树)
Description 若带点权.边权的树上一对 \((u, v)\) 为 friend,那么需要满足 \(\text{dist}(u, v) \le r_u + r_v\),其中 \(r_x\) 为 ...
- BZOJ3435 & 洛谷3920 & UOJ55:[WC2014]紫荆花之恋
https://www.lydsy.com/JudgeOnline/problem.php?id=3435 https://www.luogu.org/problemnew/show/P3920 ht ...
- 数据结构(平衡树,树分治,暴力重构):WC 2014 紫荆花之恋
[题目描述] 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来. 仔细看看的话,这棵大树实际上是一个带权 ...
- [WC 2014]紫荆花之恋
Description 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来. 仔细看看的话,这个大树实际上 ...
- UOJ#55. 【WC2014】紫荆花之恋 点分树 替罪羊树 平衡树 splay Treap
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ55.html 题解 做法还是挺容易想到的. 但是写的话…… 首先这种题如果只要求一棵树中的满足条件的点数( ...
随机推荐
- C#读取txt文件时中文乱码
解决办法 使用GB2312中文字符集 StreamReader reader = new StreamReader(txtUrl, Encoding.GetEncoding("gb2312& ...
- javascript中break和continue
1.break break语句会立即退出循环,强制执行循环后面的语句 var num = 0; for(var i=1;i<10;i++){ if(i%5 == 0){ break; } num ...
- aircrack加reaver破解带有wps的wifi
最近心血来潮,想把小区里的无线信号测试个遍.基于目前大多数路由器都支持wps,想必各位基友们都知道aircrack和reaver这 两个工具,实属破解pin码,杀人越货,居家旅行之必备良药.像以前跑r ...
- python基础===jieba模块,Python 中文分词组件
api参考地址:https://github.com/fxsjy/jieba/blob/master/README.md 安装自行百度 基本用法: import jieba #全模式 word = j ...
- jython
# -*- coding: utf-8 -*- import sys import json sys.path += ["C:/Users/yangbo/Desktop/restassure ...
- python爬虫模块之HTML解析模块
这个就比较简单了没有什么好强调的,如果返回的json 就是直接按照键值取,如果是网页就是用lxml模块的html进行xpath解析. from lxml import html import json ...
- RSA加密解密与加签验签
RSA公钥加密算法是1977年由罗纳德·李维斯特(Ron Rivest).阿迪·萨莫尔(Adi Shamir)和伦纳德·阿德曼(Leonard Adleman)一起提出的.1987年7月首次在美国公布 ...
- SPOJ Two Paths
Description 给定一个无向图,含有一定的路.从中找出两个最长的路径(每条路径有一些相通路组成)这两个路径不能经过公共的点,求何时二路径的乘积最大. 本题给出的无向图是一棵树,每边权值为1. ...
- Python 微信公众号发送消息
1. 公众号测试地址 https://mp.weixin.qq.com/debug/cgi-bin/sandboxinfo?action=showinfo&t=sandbox/index 2. ...
- Qt笔记——数据库的图形界面
1将读取的数据通过表格的方式显示出来 #ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QSqlTable ...