BZOJ 3435 Wc2014 紫荆花之恋 动态树分治+替罪羊树+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
	}
}


你可能感兴趣的:(treap,bzoj,动态树分治,替罪羊树,BZOJ3435)