标签:bzoj bzoj3435 动态树分治 替罪羊树 treap
题目大意:给定一棵树,每次添加一个节点并询问当前有多少点对满足dis(i,j)<=ri+rj 强制在线
吾辈有生之年终于把这道题切了。。。QAQ
什么?你想做这题?
1095切了么?没?去把1095切掉再说!
3065切了么?没?去把3065切掉再说!
什么?都切了?那还不会做这题??
……
算了还是说说做法吧。。。
我们抛开那些乱七八糟的,考虑朴素做法
首先式子的形式是dis(i,j)<=ri+rj,令p=lca(i,j),把式子变形可以得到dis(j,p)-rj<=ri-dis(i,p)
那么对于每个p我们维护一个Treap,把以p为根的子树中所有的dis(j,p)-rj全都扔进去
然后对于每个i,我们沿着父亲指针扫一遍,把路径上所有Treap中小于等于ri-dis(i,p)的点全都计入答案,然后把dis(i,p)-ri扔进去
但是这样会有重复的,即lca(i,j)!=p的情况,那么我们对于p的每个子树再维护一个Treap储存dis(j,p)-rj,从对应子树的Treap中减掉这样的点对就行了
这不会TLE+MLE?
废话这当然会TLE+MLE。。。
考虑树的形态是一条链的时候,时间复杂度会退化为O(n^2logn),空间复杂度也会退化到O(n^2)。
那么我们可以考虑替罪羊树的思想,即如果某个子树的大小超过了父亲节点为根的子树大小的0.88,就把以父亲节点为根的子树暴力重建
既然要重建肯定要建成相对平衡一些的树辣。。。 于是点分治不就好了辣。。。。
说起来真是简单呢~~
于是这题我写了整整七个小时。。。写到后半夜两点才过掉。。。
主要是重建之后新的子树与原先的父节点连接很不好。。。
我が生涯に、一片の悔いなし。。。
#include <set>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 100100
#define ALPHA 0.88
using namespace std;
int n;
long long last_ans;
int r[M];
namespace Graph{
struct abcd{
int to,f,next;
int ban;
}table[M<<1];
int head[M],tot=1;
int ancestor[M][17],dpt[M],dis[M];
void Add(int x,int y,int z)
{
table[++tot].to=y;
table[tot].f=z;
table[tot].next=head[x];
head[x]=tot;
}
void Build_LCA(int x)
{
int j;
for(j=1;j<=16;j++)
ancestor[x][j]=ancestor[ancestor[x][j-1]][j-1];
}
int LCA(int x,int y)
{
int j;
if(dpt[x]<dpt[y])
swap(x,y);
for(j=16;~j;j--)
if(dpt[ancestor[x][j]]>=dpt[y])
x=ancestor[x][j];
if(x==y) return x;
for(j=16;~j;j--)
if(ancestor[x][j]!=ancestor[y][j])
x=ancestor[x][j],y=ancestor[y][j];
return ancestor[x][0];
}
int Distance(int x,int y)
{
int lca=LCA(x,y);
return dis[x]+dis[y]-2*dis[lca];
}
}
struct Treap{
static queue<Treap*> bin;
Treap *ls,*rs;
int val,key;
int cnt,size;
void* operator new (size_t,int _)
{
Treap *re;
if(bin.size())
re=bin.front(),bin.pop();
else
{
static Treap *mempool,*C;
if(C==mempool)
mempool=(C=new Treap[1<<16])+(1<<16);
re=C++;
}
re->ls=re->rs=0x0;
re->val=_;re->key=rand();//信仰!
re->cnt=re->size=1;
return re;
}
void operator delete (void *p)
{
bin.push((Treap*)p);
}
void Push_Up()
{
size=cnt;
if(ls) size+=ls->size;
if(rs) size+=rs->size;
}
friend void Zig(Treap *&x)
{
Treap *y=x->ls;
x->ls=y->rs;
y->rs=x;x=y;
x->rs->Push_Up();
x->Push_Up();
}
friend void Zag(Treap *&x)
{
Treap *y=x->rs;
x->rs=y->ls;
y->ls=x;x=y;
x->ls->Push_Up();
x->Push_Up();
}
friend void Insert(Treap *&x,int y)
{
if(!x)
{
x=new (y)Treap;
return ;
}
if(y==x->val)
x->cnt++;
else if(y<x->val)
{
Insert(x->ls,y);
if(x->ls->key>x->key)
Zig(x);
}
else
{
Insert(x->rs,y);
if(x->rs->key>x->key)
Zag(x);
}
x->Push_Up();
}
friend void Decomposition(Treap *&x)
{
if(!x) return ;
Decomposition(x->ls);
Decomposition(x->rs);
delete x;x=0x0;
}
friend int Query(Treap *x,int y)
{
if(!x) return 0;
if(y<x->val)
return Query(x->ls,y);
else
return (x->ls?x->ls->size:0) + x->cnt + Query(x->rs,y);
}
};
queue<Treap*> Treap :: bin;
namespace Dynamic_TDC{
using namespace Graph;
int fa[M],v[M],T;
Treap *tree1[M],*tree2[M];
set<int> to[M];
void DFS(int x)
{
set<int>::iterator it;
v[x]=T;
for(it=to[x].begin();it!=to[x].end();it++)
{
DFS(*it);
Decomposition(tree2[*it]);
}
to[x].clear();
Decomposition(tree1[x]);
}
int Get_Size(int x,int from)
{
int i,re=1;
for(i=head[x];i;i=table[i].next)
{
if(v[table[i].to]!=T)
continue;
if(table[i].ban==T)
continue;
if(table[i].to==from)
continue;
re+=Get_Size(table[i].to,x);
}
return re;
}
int Get_Centre_Of_Gravity(int x,int from,int size,int &cg)
{
int i,re=1,flag=true;
for(i=head[x];i;i=table[i].next)
{
if(v[table[i].to]!=T)
continue;
if(table[i].ban==T)
continue;
if(table[i].to==from)
continue;
int temp=Get_Centre_Of_Gravity(table[i].to,x,size,cg);
if(temp<<1>size) flag=false;
re+=temp;
}
if(size-re<<1>size) flag=false;
if(flag) cg=x;
return re;
}
void DFS(int x,int from,int dpt,Treap *&p)
{
int i;
Insert(p,dpt-r[x]);
for(i=head[x];i;i=table[i].next)
{
if(v[table[i].to]!=T)
continue;
if(table[i].ban==T)
continue;
if(table[i].to==from)
continue;
DFS(table[i].to,x,dpt+table[i].f,p);
}
}
int Tree_Divide_And_Conquer(int x)
{
int i,size=Get_Size(x,0);
Get_Centre_Of_Gravity(x,0,size,x);
DFS(x,0,0,tree1[x]);
for(i=head[x];i;i=table[i].next)
{
if(v[table[i].to]!=T)
continue;
if(table[i].ban==T)
continue;
Treap *p=0x0;
DFS(table[i].to,x,table[i].f,p);
table[i].ban=table[i^1].ban=T;
int temp=Tree_Divide_And_Conquer(table[i].to);
tree2[temp]=p;fa[temp]=x;to[x].insert(temp);
}
return x;
}
void Rebuild(int x)
{
++T;DFS(x);
int y=fa[x];
Treap *p=tree2[x];
tree2[x]=0x0;
int temp=Tree_Divide_And_Conquer(x);
fa[temp]=y;if(y) to[y].insert(temp);
tree2[temp]=p;
}
void Insert(int x)
{
int i;
for(i=x;i;i=fa[i])
{
if(fa[i])
{
int d1=Distance(x,fa[i]);
last_ans+=Query(tree1[fa[i]],r[x]-d1);
last_ans-=Query(tree2[i],r[x]-d1);
Insert(tree2[i],d1-r[x]);
}
int d=Distance(x,i);
Insert(tree1[i],d-r[x]);
}
//前方野生替罪咩预警!
int to_rebuild=0;
for(i=x;fa[i];i=fa[i])
if( (double)tree1[i]->size/tree1[fa[i]]->size > ALPHA )
to_rebuild=fa[i];
if(to_rebuild)
Rebuild(to_rebuild);
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("3435.in","r",stdin);
freopen("3435.out","w",stdout);
#endif
srand(19980402);//我様は最強ね!にゃんははははは!~!
int i,x,y,z;
scanf("%*d%d",&n);
for(i=1;i<=n;i++)
{
scanf("%d%d%d",&x,&y,&z);
#ifdef ONLINE_JUDGE
x=x^(last_ans%1000000000);
#endif
Graph::Add(i,x,y);
Graph::Add(x,i,y);
Graph::ancestor[i][0]=x;
Graph::dpt[i]=Graph::dpt[x]+1;
Graph::dis[i]=Graph::dis[x]+y;
Graph::Build_LCA(i);
r[i]=z;
Dynamic_TDC::to[x].insert(i);
Dynamic_TDC::fa[i]=x;
Dynamic_TDC::Insert(i);
#ifdef ONLINE_JUDGE
printf("%lld\n",last_ans);
#else
printf("%I64d\n",last_ans);
#endif
}
}
BZOJ 3435 Wc2014 紫荆花之恋 动态树分治+替罪羊树+Treap
标签:bzoj bzoj3435 动态树分治 替罪羊树 treap
原文地址:http://blog.csdn.net/popoqqq/article/details/44489859