uoj 55 紫荆花之恋 动态点分治+替罪羊式重构+treap
每插入一个点,直接把它当做重心插入原树,当做是动态点分树一样维护
但这样深度会越来越大,所以我们用类似替罪羊的方法
当树失去平衡时,对子树进行一次点分,保证复杂度
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cctype>
using namespace std;
typedef long long LL;
const int M=100007;
const int N=M*80;
double alpha=0.7;
inline int rd(){
int x=0;bool f=1;char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=0;
for(;isdigit(c);c=getchar())x=x*10+c-48;
return x;
}
LL w[M];
struct Pool{
int mempool[N],tot;
Pool(){
for(int i=1;i<N;i++) mempool[i]=i;
tot=0;
}
int newmem(){
return mempool[++tot];
}
int delmem(int x){
mempool[tot--]=x;
}
}pool1,pool2,pool3;
int g[M],te;
struct edge{
int y,next;
LL d;
}e[M<<1];
void addedge(int x,int y,LL d){
e[++te].y=y;
e[te].d=d;
e[te].next=g[x];
g[x]=te;
}
struct uppp{//不同于前两题,all放在外面维护了
//多维护点分root(fa)+在fa的哪个儿子的子树下(fson)
int sub;
int fa,fson;
LL dis;
int next;
}up[N];
int hd[M],tu;
void addup(int x,int sub,int fa,int fson,LL dis){
tu=pool1.newmem();
up[tu].sub=sub;
up[tu].fa=fa;
up[tu].fson=fson;
up[tu].dis=dis;
up[tu].next=hd[x];
hd[x]=tu;
}
int n;
int idsub,idrt,ifa,ifson;
int all[M];//子树信息,动态维护点分树的话这样写方便
int que[M];
int T=0;
int vis[M],sz[M];
int size,mi,rt;
int lc[N],rc[N],cnt[N],fix[N];
LL val[N];
struct treap{
int siz,root;
treap(){siz=root=0;}
void del(int x){
if(!x) return;
pool2.delmem(x);
del(lc[x]);
del(rc[x]);
}
void delet(){
del(root);
root=0;
siz=0;
}
int newnode(LL d){
int x=pool2.newmem();
lc[x]=rc[x]=0;
cnt[x]=1;
val[x]=d;
fix[x]=rand();
return x;
}
void update(int x){
cnt[x]=1;
if(lc[x]) cnt[x]+=cnt[lc[x]];
if(rc[x]) cnt[x]+=cnt[rc[x]];
}
void rotl(int &x){
int k=rc[x];
rc[x]=lc[k];
lc[k]=x;
update(x);
update(k);
x=k;
}
void rotr(int &x){
int k=lc[x];
lc[x]=rc[k];
rc[k]=x;
update(x);
update(k);
x=k;
}
void insert(int &x,LL d){
if(!x){
x=newnode(d);
return;
}
cnt[x]++;
if(d<=val[x]){
insert(lc[x],d);
if(fix[lc[x]]<fix[x])rotr(x);
}
else{
insert(rc[x],d);
if(fix[rc[x]]<fix[x])rotl(x);
}
}
void ins(LL d){
insert(root,d);
siz++;
}
int query(int x,LL d){
if(!x) return 0;
if(d<val[x]) return query(lc[x],d);
return cnt[lc[x]]+1+query(rc[x],d);
}
LL get(LL d){
return query(root,d);
}
}a[N];
void clear(int x,int fa){
int p,y;
p=hd[x];
//清空treap时每个点把它到父亲那两个treap清空就可以了
if(p&&vis[up[p].fa]!=T){
a[up[p].sub].delet();
pool3.delmem(up[p].sub);
}
a[all[x]].delet();
pool3.delmem(all[x]);
//把需要清的静链清掉
for(p=hd[x];p&&vis[up[p].fa]!=T;p=up[p].next)
pool1.delmem(p);
hd[x]=p;
for(p=g[x];p;p=e[p].next)
if(vis[y=e[p].y]!=T&&y!=fa){
clear(y,x);
}
}
void getsz(int x,int fa){
sz[x]=1;
int p,y;
for(p=g[x];p;p=e[p].next)
if(vis[y=e[p].y]!=T&&y!=fa){
getsz(y,x);
sz[x]+=sz[y];
}
}
void getrt(int x,int fa){
int f,p,y;
f=size-sz[x];
for(p=g[x];p;p=e[p].next)
if(vis[y=e[p].y]!=T&&y!=fa){
getrt(y,x);
f=max(f,sz[y]);
}
if(f<mi) mi=f,rt=x;
}
void dfs(int x,int fa,LL dis){
addup(x,idsub,ifa,ifson,dis);
a[idrt].ins(dis-w[x]);
a[idsub].ins(dis-w[x]);
int p,y;
for(p=g[x];p;p=e[p].next)
if(vis[y=e[p].y]!=T&&y!=fa) dfs(y,x,dis+e[p].d);
}
void work(int frm){
getsz(frm,0);
mi=size=sz[frm];
getrt(frm,0);
int x=rt,p,y;
vis[x]=T;
ifa=x;
all[x]=idrt=pool3.newmem();
a[all[x]].ins(-w[x]);
for(p=g[x];p;p=e[p].next)
if(vis[y=e[p].y]!=T){
idsub=pool3.newmem();
ifson=y;
dfs(y,x,e[p].d);
}
for(p=g[x];p;p=e[p].next)
if(vis[y=e[p].y]!=T) work(y);
}
void rebuild(int x){
clear(x,0);
work(x);
}
void link(int x,int y,LL d){
if(y==0){
all[x]=pool3.newmem();
a[all[x]].ins(-w[x]);
return;
}
addedge(x,y,d);
addedge(y,x,d);
int p;
//暴力插入
all[x]=pool3.newmem();
a[all[x]].ins( -w[x] );
int tmpt=0;
for(p=hd[y];p;p=up[p].next) que[++tmpt]=p;
for(int i=tmpt;i>0;i--){//保证链的搜索顺序还是从下到上
p=que[i];
addup(x,up[p].sub,up[p].fa,up[p].fson,d+up[p].dis);
a[all[up[p].fa]].ins( d+up[p].dis-w[x] );
a[up[p].sub].ins( d+up[p].dis-w[x] );
}
//x-y
int nw=pool3.newmem();
addup(x,nw,y,x,d);
a[all[y]].ins( d-w[x] );
a[nw].ins( d-w[x] );
//判断是否要重构
int reb=0;
for(p=hd[y];p;p=up[p].next){
if((double)a[all[up[p].fa]].siz*alpha<(double)a[up[p].sub].siz)
reb=up[p].fa;
}
if(reb){
T++;//时间戳
for(p=hd[reb];p;p=up[p].next)//***
vis[up[p].fa]=T;
rebuild(reb);
}
}
LL get(int x){
LL res=a[all[x]].get(w[x]);
for(int p=hd[x];p;p=up[p].next){
res+=a[all[up[p].fa]].get(w[x]-up[p].dis);
res-=a[up[p].sub].get(w[x]-up[p].dis);
}
return res;
}
int main(){
int i,x,y,z,tt;
LL res=0;
n=rd();//滤掉测试点
n=rd();
for(i=1;i<=n;i++){
tt=res%1000000000;
x=rd()^tt;
y=rd();
w[i]=rd();
link(i,x,y);
res+=get(i)-1;
printf("%lld\n",res);
}
return 0;
}
uoj 55 紫荆花之恋 动态点分治+替罪羊式重构+treap的更多相关文章
- BZOJ3435[Wc2014]紫荆花之恋——动态点分治(替罪羊式点分树套替罪羊树)
题目描述 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来.仔细看看的话,这个大树实际上是一个带权树.每 ...
- luoguP3920 [WC2014]紫荆花之恋 动态点分治 + 替罪羊树
意外的好写..... 考虑点分 \(dis(i, j) \leq r_i + r_j\) 对于过分治中心一点\(u\),有 \(dis(i, u) - r_i = dis(j, u) + r_j\) ...
- UOJ #55 & 洛谷 P3920 紫荆花之恋 —— 动态点分治+替罪羊树
题目:http://uoj.ac/problem/55 https://www.luogu.org/problemnew/show/P3920 参考博客:https://www.cnblogs.com ...
- [WC2014]紫荆花之恋(动态点分治+替罪羊思想)
题目描述 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来.仔细看看的话,这个大树实际上是一个带权树.每 ...
- [WC2018]即时战略——动态点分治(替罪羊式点分树)
题目链接: [WC2018]即时战略 题目大意:给一棵结构未知的树,初始时除1号点其他点都是黑色,1号点是白色,每次你可以询问一条起点为白色终点任意的路径,交互库会自动返回给你这条路径上与起点相邻的节 ...
- UOJ#55. 【WC2014】紫荆花之恋 点分树 替罪羊树 平衡树 splay Treap
原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ55.html 题解 做法还是挺容易想到的. 但是写的话…… 首先这种题如果只要求一棵树中的满足条件的点数( ...
- bzoj3435 [Wc2014]紫荆花之恋(动态点分治+替罪羊树)
传送门(权限) 传送门(非权限) 题解 我终终终终终终于做出来啦!!! 作为一个没有学过替罪羊树的蒟蒻现场学了一下替罪羊树,作为一个平衡树都写数组版本的看着大佬的指针题解无语只能硬去理解然后照着抄了一 ...
- 【WC2014】紫荆花之恋(替罪羊重构点分树 & 平衡树)
Description 若带点权.边权的树上一对 \((u, v)\) 为 friend,那么需要满足 \(\text{dist}(u, v) \le r_u + r_v\),其中 \(r_x\) 为 ...
- UOJ#55. 【WC2014】紫荆花之恋
传送门 暴力思路就是每次点分治计算答案 点分治之后,条件可以变成 \(dis_i-r_i\le r_j-dis_j\) 每次只要查找 \(r_j-dis_j\) 的排名然后插入 \(dis_j-r_j ...
随机推荐
- mvc的验证
mvc的验证锦上添点花(2) 上一篇文章我们演示了通过对jquery.validate.unobtrusive.js做点小修改,如何给MVC的验证添点花 主要还是修改了onError与onSucces ...
- HDU3930(离散对数与原根)
题目:Broot 题意:给出k,m,newx的值,求方程x^k(mod m)=newx的解,其中m为素数. 解法步骤: (1)先暴力求m的原根g (2)大步小步求g^t1(mod m)=newx (3 ...
- Aliexpress API 授权流程整理
Aliexpress API 授权流程整理 前言 我零零总总用了好几个月的时间,写了一个自用的小程序,从 Aliexpress 上抓取订单的小程序.刚开始写的时候,该API还没有开放,而且没有订单 ...
- Form.Close跟Form.Dispose
关于Form.Close跟Form.Dispose 我们在Winform开发的时候,使用From.Show来显示窗口,使用Form.Close来关闭窗口.熟悉Winform开发的想必对这些非常熟悉 ...
- 性能测试工具比较:LoadRunner vs JMeter - 测试结果数据比较
对web请求(HTTP/HTML)进行性能测试,确认请求响应时间.分别使用Loadrunner和JMeter进行测试,比较测试结果. 1.LoadRunner测试web请求响应时间 1.1 编制(录 ...
- jQuery动态操作表单
<html> <head> <title>jquery表格操作</title> <script language="javascript ...
- 从零开始学C++之运算符重载(三):完善String类([]、 +、 += 运算符重载)、>>和<<运算符重载
在前面文章中使用过几次String类的例子,现在多重载几个运算符,更加完善一下,并且重载流类运算符. []运算符重载 +运算符重载 +=运算符重载 <<运算符重载 >>运算符重 ...
- 【C++自我精讲】基础系列一 指针与引用
[C++自我精讲]基础系列一 指针与引用 一 前言 指针.引用.指针与引用区别. 二 指针 变量:代码中常常通过定义变量来申请并命名存储空间,并通过变量的名字来使用这段存储空间. //变量 ...
- 根据Mob官网的天气预报接口写了一个简单的demo
第一步 自己注册一个应用,然后获取里面的 App Key,下载MobAPI SDK 然后拖入 MobAPI.framework 和 MOBFoundation.framework 到你的项目中 第二步 ...
- 【解惑】剖析float型的内存存储和精度丢失问题
问题提出:12.0f-11.9f=0.10000038,"减不尽"为什么? 现在我们就详细剖析一下浮点型运算为什么会造成精度丢失? 1.小数的二进制表示问题 首先我们要搞清楚下面两 ...