【bzoj3435】【uoj#55】[WC2014]紫荆花之恋 【动态树分治】【平衡树】
难以置信我居然今生有幸独立调出了这样一道神题!orzorzCLJ!
题目传送门
题解:
其实这道题思路不算复杂,但是代码难度特别比较高。
由于点是一个一个加进来的,我们可不可以一步一步地构建一棵动态分治树呢?我们发现,一个点是原树中某个点的儿子,那么在分治树中它也可以是这个点的儿子。我们可以直接在分治树种把它们接起来。但是当树变得特别高时,每次查询的复杂度显然会爆炸。所以我们用替罪羊树的思想,用值判一下,当某个子树变得极不平衡时重构一棵平衡的分治树。
我们设当前的分治中心为u。移项得到
但是在同一棵子树内的情况要去掉。
所以我们对每个分治中心u设两棵平衡树。第一棵维护子树内所有的值,第二棵维护子树内所有的值。新加入一个点,我们就从这个点的父亲往根爬,同时加上父亲fa[u]的第一棵平衡树的值的个数,减去自己的第二棵平衡树的值的个数。感觉还是动态树分治的常见处理方法。平衡树当然是写替罪羊树啦!
重构的时候注意一下细节就好了。
在不同OJ上的取值可能要不一样才能过。大部分OJ可过,洛谷要小一点,可过,不然会T。总之多试几次取值就差不多了。
代码好长啊!
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
inline int rd(){
register char ch=getchar();
register int res=0;
while(ch<'0'||ch>'9'){
ch=getchar();
}
while(ch>='0'&&ch<='9'){
res=res*10+ch-'0';
ch=getchar();
}
return res;
}
const int N=100005;
const double alpha=0.75;
int n,cnt,c[N],r[N],dep[N],dist[N],fa[N],siz[N],rt[N];
int idx,head[N],to[N*2],nxt[N*2],dd[N*2],vis[N],pa[N][18];
ll ans;
bool ck[N],ck2[N];
void adde(int u,int v,int d){
to[++cnt]=v;
nxt[cnt]=head[u];
dd[cnt]=d;
head[u]=cnt;
}
namespace bst{
const int M=8000005;
int cnt,val[M],siz[M],tot[M],pos[M],mmp[M],ch[M][2];
struct scapegoattree{
int rt,*goat;
void clear(int k){
if(!k){
return;
}
clear(ch[k][0]);
mmp[++mmp[0]]=k;
clear(ch[k][1]);
}
void clear(){
clear(rt);
rt=0;
}
void dfs(int k){
if(!k){
return;
}
dfs(ch[k][0]);
pos[++pos[0]]=k;
dfs(ch[k][1]);
}
void build(int &k,int l,int r){
if(l>r){
k=0;
return;
}
int mid=(l+r)/2;
k=pos[mid];
build(ch[k][0],l,mid-1);
build(ch[k][1],mid+1,r);
siz[k]=siz[ch[k][0]]+siz[ch[k][1]]+1;
tot[k]=tot[ch[k][0]]+tot[ch[k][1]]+1;
}
void rebuild(int &k){
pos[0]=0;
dfs(k);
build(k,1,pos[0]);
}
void insert(int &k,int x){
if(!k){
k=mmp[0]?mmp[mmp[0]--]:++cnt;
ch[k][0]=ch[k][1]=0;
val[k]=x;
siz[k]=tot[k]=1;
return;
}
siz[k]++;
tot[k]++;
if(x<=val[k]){
insert(ch[k][0],x);
}else{
insert(ch[k][1],x);
}
if(tot[k]*alpha<max(tot[ch[k][0]],tot[ch[k][1]])){
goat=&k;
}
}
void insert(int x){
goat=0;
insert(rt,x);
if(goat){
rebuild(*goat);
}
}
int get(int x){
int k=rt,res=0;
while(k){
if(x<val[k]){
k=ch[k][0];
}else{
res+=siz[ch[k][0]]+1;
k=ch[k][1];
}
}
return res;
}
}sgt[N][2];
}
int lca(int u,int v){
if(dep[u]<dep[v]){
swap(u,v);
}
int d=dep[u]-dep[v];
for(int i=0;(1<<i)<=d;i++){
if(d&(1<<i)){
u=pa[u][i];
}
}
if(u==v){
return u;
}
for(int i=17;i>=0;i--){
if(pa[u][i]!=pa[v][i]){
u=pa[u][i];
v=pa[v][i];
}
}
return pa[u][0];
}
int dis(int u,int v){
int tmp=lca(u,v);
return dist[u]-dist[tmp]+dist[v]-dist[tmp];
}
int mi,root,sz;
void dfsvis(int pre,int u){
bst::sgt[u][0].clear();
bst::sgt[u][1].clear();
vis[u]=idx;
int v;
for(int i=head[u];i;i=nxt[i]){
v=to[i];
if(v!=pre&&!ck2[v]){
dfsvis(u,v);
}
}
}
int dfsroot(int pre,int u){
int mx=0,siz=1,v,tmp;
for(int i=head[u];i;i=nxt[i]){
v=to[i];
if(v!=pre&&vis[v]==idx&&!ck[v]&&!ck2[v]){
tmp=dfsroot(u,v);
mx=max(mx,tmp);
siz+=tmp;
}
}
mx=max(mx,sz-siz);
if(mx<mi){
mi=mx;
root=u;
}
return siz;
}
int dfssize(int pre,int u){
int siz=1,v;
for(int i=head[u];i;i=nxt[i]){
v=to[i];
if(v!=pre&&vis[v]==idx&&!ck[v]&&!ck2[v]){
siz+=dfssize(u,v);
}
}
return siz;
}
void build(int pre,int u,int d,bst::scapegoattree *t){
t->insert(d-r[u]);
int v;
for(int i=head[u];i;i=nxt[i]){
v=to[i];
if(v!=pre&&vis[v]==idx&&!ck[v]&&!ck2[v]){
build(u,v,d+dd[i],t);
}
}
}
void dfs(int u){
ck[u]=true;
build(0,u,0,&bst::sgt[u][0]);
int v;
for(int i=head[u];i;i=nxt[i]){
v=to[i];
if(vis[v]==idx&&!ck[v]&&!ck2[v]){
mi=sz=dfssize(u,v);
dfsroot(u,v);
fa[root]=u;
rt[root]=v;
siz[root]=sz;
build(0,v,dd[i],&bst::sgt[root][1]);
dfs(root);
}
}
}
void dfsclear(int pre,int u){
ck[u]=false;
int v;
for(int i=head[u];i;i=nxt[i]){
v=to[i];
if(v!=pre&&!ck2[v]){
dfsclear(u,v);
}
}
}
void rebuild(int pre,int u){
int tmp=pre;
while(tmp){
ck2[tmp]=true;
tmp=fa[tmp];
}
idx++,dfsvis(pre,u);
dfsroot(pre,u);
fa[root]=pre;
rt[root]=u;
siz[root]=sz;
if(pre){
build(0,u,dis(pre,u),&bst::sgt[root][1]);
}
dfs(root);
dfsclear(pre,u);
tmp=pre;
while(tmp){
ck2[tmp]=false;
tmp=fa[tmp];
}
}
int main(){
rd(),n=rd();
for(int i=1;i<=n;i++){
fa[i]=pa[i][0]=rd()^(ans%1000000000),c[i]=rd(),r[i]=rd();
siz[i]=1;
rt[i]=i;
if(i==1){
bst::sgt[1][0].insert(c[i]-r[i]);
puts("0");
continue;
}
adde(pa[i][0],i,c[i]);
adde(i,pa[i][0],c[i]);
dep[i]=dep[pa[i][0]]+1;
dist[i]=dist[pa[i][0]]+c[i];
for(int j=1;(1<<j)<=dep[i];j++){
pa[i][j]=pa[pa[i][j-1]][j-1];
}
ans+=bst::sgt[fa[i]][0].get(r[i]-dis(fa[i],i));
for(int u=fa[i];fa[u];u=fa[u]){
ans+=bst::sgt[fa[u]][0].get(r[i]-dis(fa[u],i));
ans-=bst::sgt[u][1].get(r[i]-dis(fa[u],i));
}
int tmp=0;
bst::sgt[i][0].insert(0-r[i]);
for(int u=i;fa[u];u=fa[u]){
siz[fa[u]]++;
bst::sgt[fa[u]][0].insert(dis(fa[u],i)-r[i]);
bst::sgt[u][1].insert(dis(fa[u],i)-r[i]);
if(siz[fa[u]]*alpha<siz[u]){
tmp=fa[u];
}
}
if(tmp){
mi=sz=siz[tmp];
rebuild(fa[tmp],rt[tmp]);
}
printf("%lld\n",ans);
}
return 0;
}