【BZOJ3435】[Wc2014]紫荆花之恋

Description

强强和萌萌是一对好朋友。有一天他们在外面闲逛,突然看到前方有一棵紫荆树。这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来。仔细看看的话,这个大树实际上是一个带权树。每个时刻它会长出一个新的叶子节点。每个节点上有一个可爱的小精灵,新长出的节点上也会同时出现一个新的小精灵。小精灵是很萌但是也很脆弱的生物,每个小精灵 i 都有一个感受能力值Ri ,小精灵 i, j 成为朋友当且仅当在树上 i 和 j 的距离 dist(i,j) ≤ Ri + R! ,其中 dist(i, j)表示在这个树上从 i 到 j 的唯一路径上所有边的边权和。强强和萌萌很好奇每次新长出一个叶子节点之后,这个树上总共有几对朋友。  
我们假定这个树一开始为空,节点按照加入的顺序从 1开始编号。由于强强非常好奇, 你必须在他每次出现新节点后马上给出总共的朋友对数,不能拖延哦。

Input

共有 n + 2 行。 
第一行包含一个正整数,表示测试点编号。 
第二行包含一个正整数 n ,表示总共要加入的节点数。 
我们令加入节点前的总共朋友对数是 last_ans,在一开始时它的值为0。 
接下来 n 行中第 i 行有三个数 ai, bi, ri,表示节点  i  的父节点的编号为 ai xor (last_ans mod 10^9)   (其中xor 表示异或,mod  表示取余,数据保证这样操作后得到的结果介于 1到i  –  1之间),与父节点之间的边权为 ci,节点 i 上小精灵的感受能力值为r!。 
注意 a1 = c1 = 0,表示 1 号点是根节点,对于 i > 1,父节点的编号至少为1。

Output

包含 n 行,每行输出1 个整数, 表示加入第 i 个点之后,树上有几对朋友。

Sample Input

0
5
0 0 6
1 2 4
0 9 4
0 5 5
0 2 4

Sample Output

0
1
2
4
7

HINT

1<=Ci<=10000
Ai<=2*10^9
Ri<=10^9
N<=100000

题解:在GXZ的蛊惑下,特地去学了一发SBT~

显然要将题中的式子拆一下:dis(i,j)<=ri+rj  -> dis(i,lca)+dis(j,lca)<=ri+rj -> dis(i,lca)-ri<=rj-dis(j,lca)。

所以我们对点分树上的每个节点都维护一个SBT记录所有dis(i,x)-ri,然后每次加点时,在点分树上到根的路径上的每个点的SBT都查一下就行了。由于有重复计算,所以对于每个点我们还要维护一个SBT记录所有dis(i,fa[x])-ri,查询时减去即可。

但是动态加点怎么办?将点分树变成替罪的即可。

其实代码并不是特别长,如果TLE了一定是写挂了~

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
typedef long long ll;
const int maxn=100010;
const ll mod=1000000000;
int n,m,tot,cnt,mn,root;
ll ans;
struct sbt
{
int siz,ch[2],val;
}t[20000005];
vector<int> ch[maxn];
int r[maxn],f[19][maxn],siz[maxn],dep[maxn],head[maxn],next[maxn<<1],to[maxn<<1],vis[maxn],p[maxn];
int r1[maxn],r2[maxn],fa[maxn],dd[maxn],Log[maxn];
queue<int> q;
int mem;
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-')f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
void pushup(int x) {t[x].siz=t[t[x].ch[0]].siz+t[t[x].ch[1]].siz+1;}
void rotate(int &x,int d)
{
int y=t[x].ch[d];
t[x].ch[d]=t[y].ch[d^1],t[y].ch[d^1]=x;
pushup(x),pushup(y),x=y;
}
void maintain(int &x,int d)
{
if(t[t[t[x].ch[d]].ch[d]].siz>t[t[x].ch[d^1]].siz)
rotate(x,d);
else if(t[t[t[x].ch[d]].ch[d^1]].siz>t[t[x].ch[d^1]].siz)
rotate(t[x].ch[d],d^1),rotate(x,d);
else return;
maintain(t[x].ch[0],0),maintain(t[x].ch[1],1);
maintain(x,0),maintain(x,1);
}
void insert(int &x,int y)
{
if(!x)
{
mem--;
x=q.front(),q.pop();
t[x].siz=1,t[x].val=y,t[x].ch[0]=t[x].ch[1]=0;
return ;
}
int d=(y>=t[x].val);
t[x].siz++,insert(t[x].ch[d],y);
maintain(x,d);
}
int query(int x,int y)
{
if(!x) return 0;
if(t[x].val<=y) return query(t[x].ch[1],y)+1+t[t[x].ch[0]].siz;
return query(t[x].ch[0],y);
}
void del(int &x)
{
if(!x) return ;
mem++;
del(t[x].ch[0]),del(t[x].ch[1]),t[x].siz=t[x].val=0,q.push(x),x=0;
}
void getrt(int x,int fa)
{
siz[x]=1;
int i,tmp=0;
for(i=head[x];i!=-1;i=next[i]) if(to[i]!=fa&&vis[to[i]]==2)
getrt(to[i],x),siz[x]+=siz[to[i]],tmp=max(tmp,siz[to[i]]);
tmp=max(tmp,tot-siz[x]);
if(tmp<mn) mn=tmp,root=x;
}
void solve(int x)
{
vis[x]=1;
for(int i=head[x];i!=-1;i=next[i]) if(vis[to[i]]==2)
tot=siz[to[i]],mn=1<<30,getrt(to[i],x),fa[root]=x,solve(root);
}
void add(int a,int b)
{
to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
}
int lca(int a,int b)
{
if(dd[a]<dd[b]) swap(a,b);
int i;
for(i=Log[dd[a]-dd[b]];i>=0;i--) if(dd[f[i][a]]>=dd[b]) a=f[i][a];
if(a==b) return b;
for(i=Log[dd[a]];i>=0;i--) if(f[i][a]!=f[i][b]) a=f[i][a],b=f[i][b];
return f[0][a];
}
int dis(int a,int b)
{
return dep[a]+dep[b]-2*dep[lca(a,b)];
}
int main()
{
rd(),n=rd();
memset(head,-1,sizeof(head));
int i,j,a,b,u,last,flast;
mem=20000000;
for(i=1;i<=20000000;i++) q.push(i);
rd(),rd(),r[1]=rd(),siz[1]=1,dd[1]=1,ch[1].push_back(1),insert(r1[1],-r[1]);
for(i=2;i<=n;i++) Log[i]=Log[i>>1]+1;
printf("0\n");
for(i=2;i<=n;i++)
{
a=rd()^(ans%mod),b=rd(),r[i]=rd();
add(a,i),add(i,a),dep[i]=dep[a]+b,dd[i]=dd[a]+1;
f[0][i]=a,fa[i]=a;
for(j=1;j<=Log[dd[i]];j++) f[j][i]=f[j-1][f[j-1][i]];
for(last=0,u=i;u;u=fa[u])
{
ans+=query(r1[u],r[i]-dis(i,u));
ch[u].push_back(i),insert(r1[u],dis(i,u)-r[i]),siz[u]++;
if(fa[u])
{
ans-=query(r2[u],r[i]-dis(i,fa[u]));
insert(r2[u],dis(i,fa[u])-r[i]);
}
if(fa[u]&&siz[u]*1.0>(siz[fa[u]]+1)*0.88) last=fa[u];
}
if(last)
{
flast=fa[last],vis[flast]=3;
for(p[0]=j=0;j<(int)ch[last].size();j++) p[++p[0]]=ch[last][j];
for(j=1;j<=p[0];j++) ch[p[j]].clear(),del(r1[p[j]]),del(r2[p[j]]),vis[p[j]]=2;
tot=p[0],mn=1<<30,getrt(last,0),fa[root]=flast,solve(root);
for(j=1;j<=p[0];j++)
{
for(u=p[j];u!=flast;u=fa[u])
{
ch[u].push_back(p[j]);
insert(r1[u],dis(p[j],u)-r[p[j]]);
if(fa[u]) insert(r2[u],dis(p[j],fa[u])-r[p[j]]);
}
}
}
printf("%lld\n",ans);
}
return 0;
}

【BZOJ3435】[Wc2014]紫荆花之恋 替罪点分树+SBT的更多相关文章

  1. 【bzoj3435】[Wc2014]紫荆花之恋 替罪点分树套SBT

    题目描述 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来.仔细看看的话,这个大树实际上是一个带权树.每 ...

  2. BZOJ3435[Wc2014]紫荆花之恋——动态点分治(替罪羊式点分树套替罪羊树)

    题目描述 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来.仔细看看的话,这个大树实际上是一个带权树.每 ...

  3. BZOJ3435: [Wc2014]紫荆花之恋(替罪羊树,Treap)

    Description 强强和萌萌是一对好朋友.有一天他们在外面闲逛,突然看到前方有一棵紫荆树.这已经是紫荆花飞舞的季节了,无数的花瓣以肉眼可见的速度从紫荆树上长了出来.仔细看看的话,这个大树实际上是 ...

  4. bzoj3435 [Wc2014]紫荆花之恋

    如果这棵树不变的话,就是一个裸的点分树套平衡树,式子也很好推$di+dj<=ri+rj$,$ri-di>=dj-rj$ 平衡树维护$dj-rj$,然后查$ri-di$的$rank$即可. ...

  5. bzoj3435 [Wc2014]紫荆花之恋(动态点分治+替罪羊树)

    传送门(权限) 传送门(非权限) 题解 我终终终终终终于做出来啦!!! 作为一个没有学过替罪羊树的蒟蒻现场学了一下替罪羊树,作为一个平衡树都写数组版本的看着大佬的指针题解无语只能硬去理解然后照着抄了一 ...

  6. luoguP3920 [WC2014]紫荆花之恋 动态点分治 + 替罪羊树

    意外的好写..... 考虑点分 \(dis(i, j) \leq r_i + r_j\) 对于过分治中心一点\(u\),有 \(dis(i, u) - r_i = dis(j, u) + r_j\) ...

  7. bzoj 3435: [Wc2014]紫荆花之恋 替罪羊树维护点分治 && AC400

    3435: [Wc2014]紫荆花之恋 Time Limit: 240 Sec  Memory Limit: 512 MBSubmit: 159  Solved: 40[Submit][Status] ...

  8. BZOJ 3435: [Wc2014]紫荆花之恋

    二次联通门 : BZOJ 3435: [Wc2014]紫荆花之恋 二次联通门 : luogu P3920 [WC2014]紫荆花之恋 /* luogu P3920 [WC2014]紫荆花之恋 怀疑人生 ...

  9. BZOJ3435 & 洛谷3920 & UOJ55:[WC2014]紫荆花之恋

    https://www.lydsy.com/JudgeOnline/problem.php?id=3435 https://www.luogu.org/problemnew/show/P3920 ht ...

随机推荐

  1. LeetCode OJ-- Search a 2D Matrix

    https://oj.leetcode.com/problems/search-a-2d-matrix/ 具有数据递增性质的一个二维数组,对它进行二分搜索. 首先搜索target所在的行,再找列. c ...

  2. AC日记——[HNOI2007]紧急疏散evacuate bzoj 1189

    [HNOI2007]紧急疏散evacuate 思路: 处理每个人到门的最短路: 然后二分答案: s向人连边流量1: 人向门拆分后的点连边流量1(拆成400,前一个点连当前点流量INF): 然后门向t连 ...

  3. window下Apache-http-server(httpd-2.4.12)安装与配置

    由于Apache官网改变策略(2015年1月左右),官网不再提供Apache-http-server的windows的编译版本,但是提供了几个第三方的版本 http://httpd.apache.or ...

  4. bzoj 2889: Tree Conundrum

    2889: Tree Conundrum Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 61  Solved: 37[Submit][Status][ ...

  5. Java泛型构造函数

    1.概述 我们之前讨论过Java Generics的基础知识.在本文中,我们将了解Java中的通用构造函数. 泛型构造函数是至少需要有一个泛型类型参数的构造函数.我们将看到泛型构造函数并不都是在泛型类 ...

  6. 输出n行等腰三角形(符号为*)

    输出n行等腰三角形(符号为*) 1. 核心操作 First, 找出每一行的第一个*之前需要的空格个数 规律1:设该等腰三角形一共N行, 那么第n行的第一个*之前需要的空格个数就为N-n个空格 推导过程 ...

  7. 使用PreloadJS加载图片资源

    一. 使用createjs里的LoadQueue函数实现异步加载图片,监听加载进度 1.实例对象LoadQueue加载队列对象 var queue = new createjs.LoadQueue(f ...

  8. Your build settings specify a provisioning profile with the UUID, no provisioning profile was

    http://blog.csdn.net/rbyyyblog/article/details/12220875 在Archive项目时,出现了“Your build settings specify ...

  9. 【redis】redis实现API接口调用调用次数的限制

    redis实现API接口调用调用次数的限制 参考地址:https://bbs.csdn.net/topics/391856106?page=1 参考地址:https://www.cnblogs.com ...

  10. Eclipse中src/main/resources配置文件启动问题

    项目pom文件有做修改如下的时候,还没有进行mvn clean install 启动test项目中的appcontext会 可以手动清空 然后就可以了. 出现如下问题的原因是 配置文件默认输出到tar ...