python画图绘制紫荆花_UOJ#55. 【WC2014】紫荆花之恋 点分树 替罪羊树 平衡树 splay Treap...

原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ55.html

题解

做法还是挺容易想到的。

但是写的话……

首先这种题如果只要求一棵树中的满足条件的点数(不需要在加点的同时维护答案),那么显然可以点分治:

假设当前点分中心为 x,设点 y 与 x 的距离为 d[y] ,然后,我们把 $d[a] + d[b] \leq r[a] + r[b]$ 移一下项,得到:

$$d[a]-r[a]\leq r[b] - d[b]$$

那么,我们只需要对于每一个点 b 求出与它不在 x 的同一个子树的节点 a 的个数,a 要满足 $d[a]-r[a]\leq r[b]-d[b]$ 。这个东西显然是可以用数据结构维护的。

具体用什么呢?

再说。

现在我们要动态维护答案。考虑如果可以离线怎么做:

对最终的树建一个点分树,也就是搞一个动态点分治。对于每一个点分中心,维护他控制的区域内所有节点的 d[a]-r[a] ;对于他的每一个子树,也维护一下这个东西。

那么加入一个点的时候,我们只要在点分树上走一趟,通过维护的信息更新答案的同时加入当前节点的贡献。

所以我们要的数据结构得支持插入和询问排名,那么自然选用平衡树。

所以离线的复杂度是 $O(n\log^2 n)$ 。

然而题目要求强制在线。

怎么办?

定期重构点分树?复杂度好像是 $O(n\sqrt n \log  n)$ 。好像和暴力得分一样……

定期重构太naive了,我们给他升个级!

替罪羊树:当点分树的一个子树划分的过度不均匀的时候,重构子树。

恭喜你得到了一个 $O(n\log^3 n)$ 的算法。

接下来是写代码和调代码的欢♂乐时光。

可怕的是,这题还卡常数……

下面给出两份代码,一个是splay(68331ms的那个),一个是非旋Treap(107878ms)。

代码1 - splay

#pragma GCC optimize("Ofast","inline")

#include

#define clr(x) memset(x,0,sizeof (x))

#define For(i,a,b) for (int i=a;i<=b;i++)

#define Fod(i,b,a) for (int i=b;i>=a;i--)

#define pb push_back

#define mp make_pair

#define fi first

#define se second

#define _SEED_ ('C'+'L'+'Y'+'A'+'K'+'I'+'O'+'I')

#define outval(x) printf(#x" = %d\n",x)

#define outvec(x) printf("vec "#x" = ");for (auto _v : x)printf("%d ",_v);puts("")

#define outtag(x) puts("----------"#x"----------")

using namespace std;

typedef long long LL;

LL read(){

LL x=0,f=0;

char ch=getchar();

while (!isdigit(ch))

f|=ch=='-',ch=getchar();

while (isdigit(ch))

x=(x<<1)+(x<<3)+(ch^48),ch=getchar();

return f?-x:x;

}

const int N=100005,INF=1.05e9,mod=1e9;

const double checkval=0.80;

namespace spl{

const int S=N*100;

int son[S][2],fa[S],val[S],size[S];

int cnt=0;

namespace cly{

int st[S],top=0;

inline int new_node(){

return top?st[top--]:++cnt;

}

inline void Recover(int x){

st[++top]=x;

son[x][0]=son[x][1]=fa[x]=val[x]=size[x]=0;

}

}

using cly::new_node;

using cly::Recover;

#define ls son[x][0]

#define rs son[x][1]

int new_node(int v){

int x=new_node();

val[x]=v;

return x;

}

inline void pushup(int x){

size[x]=size[ls]+size[rs]+1;

}

inline int wson(int x){

return son[fa[x]][1]==x;

}

void rotate(int x){

int y=fa[x],z=fa[y],L=son[y][1]==x,R=L^1;

if (z)

son[z][son[z][1]==y]=x;

fa[x]=z,fa[y]=x,fa[son[x][R]]=y;

son[y][L]=son[x][R],son[x][R]=y;

pushup(y),pushup(x);

}

void splay(int x){

for (int y=fa[x];fa[x];rotate(x),y=fa[x])

if (fa[y])

rotate(wson(x)==wson(y)?y:x);

}

inline void Ins(int &a,int v){

register int x=a,c=0;

int f=0;

while (x){

c++;

size[x]++;

f=x;

x=v

}

val[son[f][v>=val[f]]=x=new_node()]=v,fa[x]=f,size[x]=1;

if (!a||c>30)

splay(a=x);

}

int Query(int &rt,int v){

int ans=0,c=0;

register int x=rt,p=0;

while (x){

p=x,c++;

if (val[x]<=v)

ans+=size[ls]+1,x=rs;

else

x=ls;

}

if (p&&c>30)

splay(rt=p);

return ans;

}

void Remove(int x){

if (x)

Remove(ls),Remove(rs),Recover(x);

}

int id[N];

void Build(int &x,int L,int R,int f){

if (L>R)

return;

int mid=(L+R)>>1;

fa[x=id[mid]]=f;

Build(ls,L,mid-1,x);

Build(rs,mid+1,R,x);

pushup(x);

}

void Build(int &x,vector &v){

if (v.empty())

return;

int n=0;

sort(v.begin(),v.end());

for (auto i : v)

id[++n]=new_node(i);

Build(x,1,n,0);

}

#undef ls

#undef rs

}

int Test,n;

LL ans=0;

vector e[N];

int fa[N][20],depth[N],len[N];

int LCA(int x,int y){

if (depth[x]

swap(x,y);

Fod(i,16,0)

if (depth[x]-(1<=depth[y])

x=fa[x][i];

if (x==y)

return x;

Fod(i,16,0)

if (fa[x][i]!=fa[y][i])

x=fa[x][i],y=fa[y][i];

return fa[x][0];

}

int Dis(int x,int y){

return len[x]+len[y]-2*len[LCA(x,y)];

}

int r[N];

namespace dt{

int fa[N],size[N],mxs[N],depth[N];

int rt[N],rtf[N];

int node_cnt=0;

void Init(){

clr(fa),clr(size),clr(mxs),clr(depth),clr(rt),clr(rtf);

depth[0]=-1,node_cnt++;

size[1]=1,mxs[1]=depth[1]=rt[1]=0;

spl::Ins(rt[1],0-r[1]);

}

int id[N],idc=0;

void dfs(int x,int pre,int d){

id[++idc]=x;

for (auto y : e[x])

if (y!=pre&&depth[y]>=d)

dfs(y,x,d);

}

int sz[N],msz[N],RT,Size;

void dfs2(int x,int pre){

sz[x]=1,msz[x]=0;

for (auto y : e[x])

if (y!=pre&&!size[y]){

dfs2(y,x);

sz[x]+=sz[y];

msz[x]=max(msz[x],sz[y]);

}

msz[x]=max(msz[x],Size-sz[x]);

if (!RT||msz[x]

RT=x;

}

vector id1,id2;

void dfs3(int x,int pre,int anc){

sz[x]=1;

id1.pb(Dis(x,anc)-r[x]);

if (fa[anc])

id2.pb(Dis(x,fa[anc])-r[x]);

for (auto y : e[x])

if (y!=pre&&!size[y])

dfs3(y,x,anc),sz[x]+=sz[y];

}

void build(int x,int f,int n){

RT=0,Size=n;

dfs2(x,0);

x=RT;

fa[x]=f,depth[x]=depth[f]+1,size[x]=n,mxs[x]=msz[x];

id1.clear(),id2.clear();

dfs3(x,0,x);

spl::Build(rt[x],id1);

spl::Build(rtf[x],id2);

for (auto y : e[x])

if (!size[y])

build(y,x,sz[y]);

}

void Rebuild(int x,int f){

idc=0;

dfs(x,0,depth[x]);

For(_t,1,idc){

int i=id[_t];

spl::Remove(rt[i]),spl::Remove(rtf[i]);

depth[i]=size[i]=fa[i]=mxs[i]=rt[i]=rtf[i]=0;

}

build(x,f,idc);

}

void Ins(int x,int f){

static vector v;

fa[x]=f,depth[x]=depth[f]+1;

rt[x]=rtf[x]=0;

v.clear();

for (int i=x;i;i=fa[i]){

v.pb(i),size[i]++;

mxs[fa[i]]=max(mxs[fa[i]],size[i]);

spl::Ins(rt[i],Dis(i,x)-r[x]);

if (fa[i])

spl::Ins(rtf[i],Dis(fa[i],x)-r[x]);

}

node_cnt++;

reverse(v.begin(),v.end());

for (auto i : v)

if (mxs[i]>checkval*size[i]){

Rebuild(i,fa[i]);

break;

}

if (size[x]>1)

ans+=spl::Query(rt[x],r[x])-1;

for (int i=x,f,d;depth[i];i=f){

f=fa[i],d=Dis(f,x);

ans+=spl::Query(rt[f],r[x]-d)-spl::Query(rtf[i],r[x]-d);

}

}

}

int main(){

Test=read(),n=read();

For(i,1,n){

int f=read()^(ans%mod),c=read();

r[i]=read();

if (!f){

dt::Init();

printf("%lld\n",ans);

continue;

}

assert(1<=f&&f

e[i].pb(f),e[f].pb(i);

fa[i][0]=f;

For(j,1,16)

fa[i][j]=fa[fa[i][j-1]][j-1];

depth[i]=depth[f]+1;

len[i]=len[f]+c;

dt::Ins(i,f);

printf("%lld\n",ans);

}

return 0;

}

代码2 - Treap(非旋)

#pragma GCC optimize("Ofast","inline")

#include

#define clr(x) memset(x,0,sizeof (x))

#define For(i,a,b) for (int i=a;i<=b;i++)

#define Fod(i,b,a) for (int i=b;i>=a;i--)

#define pb push_back

#define mp make_pair

#define fi first

#define se second

#define _SEED_ ('C'+'L'+'Y'+'A'+'K'+'I'+'O'+'I')

#define outval(x) printf(#x" = %d\n",x)

#define outvec(x) printf("vec "#x" = ");for (auto _v : x)printf("%d ",_v);puts("")

#define outtag(x) puts("----------"#x"----------")

using namespace std;

typedef long long LL;

LL read(){

LL x=0,f=0;

char ch=getchar();

while (!isdigit(ch))

f|=ch=='-',ch=getchar();

while (isdigit(ch))

x=(x<<1)+(x<<3)+(ch^48),ch=getchar();

return f?-x:x;

}

const int N=100005,INF=1.05e9,mod=1e9;

const double checkval=0.80;

int randint(){

#ifdef windows

return (rand()<<15)^rand();

#else

return rand();

#endif

}

namespace Treap{

const int S=N*100;

int son[S][2],val[S],ckv[S],size[S];

int cnt=0;

namespace cly{

int st[S],top=0;

inline int new_node(){

return top?st[top--]:++cnt;

}

inline void Recover(int x){

st[++top]=x,son[x][0]=son[x][1]=val[x]=size[x]=0;

}

}

#define ls son[x][0]

#define rs son[x][1]

int new_node(int v){

int x=cly::new_node();

val[x]=v,ckv[x]=randint(),size[x]=1;

return x;

}

void pushup(int x){

size[x]=size[ls]+size[rs]+1;

}

int Merge(int x,int y){

if (!x||!y)

return x+y;

if (ckv[x]

son[x][1]=Merge(son[x][1],y),pushup(x);

return x;

}

else {

son[y][0]=Merge(x,son[y][0]),pushup(y);

return y;

}

}

pair Split(int x,int k){

if (!x)

return mp(0,0);

if (k<=size[ls]){

pair p=Split(ls,k);

ls=p.se,pushup(x);

return mp(p.fi,x);

}

else {

pair p=Split(rs,k-size[ls]-1);

rs=p.fi,pushup(x);

return mp(x,p.se);

}

}

int _Rank(int x,int v){

return x?(val[x]>v?_Rank(ls,v):size[ls]+1+_Rank(rs,v)):0;

}

int Rank(int x,int v){

return _Rank(x,v-1);

}

int Query(int x,int v){

return _Rank(x,v);

}

int id[N];

int tL[N],tR[N],lcnt,rcnt;

void Build(int &x,int L,int R){

if (L>R)

return;

int Mi=L;

For(i,L+1,R)

if (ckv[id[i]]

Mi=i;

swap(id[Mi],id[R]);

x=id[R];

lcnt=rcnt=0;

For(i,L,R-1)

if (val[id[i]]<=val[x])

tL[++lcnt]=id[i];

else

tR[++rcnt]=id[i];

int c=L-1;

For(i,1,lcnt)

id[++c]=tL[i];

int mid=c;

For(i,1,rcnt)

id[++c]=tR[i];

Build(ls,L,mid);

Build(rs,mid+1,R-1);

pushup(x);

}

void Build(int &x,vector &v){

if (v.empty())

return;

int n=0;

for (auto i : v)

id[++n]=new_node(i);

Build(x,1,n);

}

void Ins(int &x,int v){

pair p=Split(x,_Rank(x,v));

x=Merge(p.fi,Merge(new_node(v),p.se));

}

void Remove(int x){

if (x)

Remove(ls),Remove(rs),cly::Recover(x);

}

#undef ls

#undef rs

}

int Test,n;

LL ans=0;

vector e[N];

int fa[N][20],depth[N],len[N];

int LCA(int x,int y){

if (depth[x]

swap(x,y);

Fod(i,16,0)

if (depth[x]-(1<=depth[y])

x=fa[x][i];

if (x==y)

return x;

Fod(i,16,0)

if (fa[x][i]!=fa[y][i])

x=fa[x][i],y=fa[y][i];

return fa[x][0];

}

int Dis(int x,int y){

return len[x]+len[y]-2*len[LCA(x,y)];

}

int r[N];

namespace dt{

int fa[N],size[N],mxs[N],depth[N];

int rt[N],rtf[N];

int node_cnt=0;

void Init(){

clr(fa),clr(size),clr(mxs),clr(depth),clr(rt),clr(rtf);

depth[0]=-1,node_cnt++;

size[1]=1,mxs[1]=depth[1]=rt[1]=0;

Treap::Ins(rt[1],0-r[1]);

}

int id[N],idc=0;

void dfs(int x,int pre,int d){

id[++idc]=x;

for (auto y : e[x])

if (y!=pre&&depth[y]>=d)

dfs(y,x,d);

}

int sz[N],msz[N],RT,Size;

void dfs2(int x,int pre){

sz[x]=1,msz[x]=0;

for (auto y : e[x])

if (y!=pre&&!size[y]){

dfs2(y,x);

sz[x]+=sz[y];

msz[x]=max(msz[x],sz[y]);

}

msz[x]=max(msz[x],Size-sz[x]);

if (!RT||msz[x]

RT=x;

}

vector id1,id2;

void dfs3(int x,int pre,int anc){

sz[x]=1;

id1.pb(Dis(x,anc)-r[x]);

if (fa[anc])

id2.pb(Dis(x,fa[anc])-r[x]);

for (auto y : e[x])

if (y!=pre&&!size[y])

dfs3(y,x,anc),sz[x]+=sz[y];

}

void build(int x,int f,int n){

RT=0,Size=n;

dfs2(x,0);

x=RT;

fa[x]=f,depth[x]=depth[f]+1,size[x]=n,mxs[x]=msz[x];

id1.clear(),id2.clear();

dfs3(x,0,x);

Treap::Build(rt[x],id1);

Treap::Build(rtf[x],id2);

for (auto y : e[x])

if (!size[y])

build(y,x,sz[y]);

}

void Rebuild(int x,int f){

idc=0;

dfs(x,0,depth[x]);

For(_t,1,idc){

int i=id[_t];

Treap::Remove(rt[i]),Treap::Remove(rtf[i]);

depth[i]=size[i]=fa[i]=mxs[i]=rt[i]=rtf[i]=0;

}

build(x,f,idc);

}

void Ins(int x,int f){

static vector v;

fa[x]=f,depth[x]=depth[f]+1;

rt[x]=rtf[x]=0;

v.clear();

for (int i=x;i;i=fa[i]){

v.pb(i),size[i]++;

mxs[fa[i]]=max(mxs[fa[i]],size[i]);

Treap::Ins(rt[i],Dis(i,x)-r[x]);

if (fa[i])

Treap::Ins(rtf[i],Dis(fa[i],x)-r[x]);

}

node_cnt++;

reverse(v.begin(),v.end());

for (auto i : v)

if (mxs[i]>checkval*size[i]){

Rebuild(i,fa[i]);

break;

}

if (size[x]>1)

ans+=Treap::Query(rt[x],r[x])-1;

for (int i=x,f,d;depth[i];i=f){

f=fa[i],d=Dis(f,x);

ans+=Treap::Query(rt[f],r[x]-d)-Treap::Query(rtf[i],r[x]-d);

}

}

}

int main(){

srand(_SEED_);

Test=read(),n=read();

For(i,1,n){

int f=read()^(ans%mod),c=read();

r[i]=read();

if (!f){

dt::Init();

printf("%lld\n",ans);

continue;

}

e[i].pb(f),e[f].pb(i);

fa[i][0]=f;

For(j,1,16)

fa[i][j]=fa[fa[i][j-1]][j-1];

depth[i]=depth[f]+1;

len[i]=len[f]+c;

dt::Ins(i,f);

printf("%lld\n",ans);

}

return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值