码迷,mamicode.com
首页 > 编程语言 > 详细

【树链剖分】【树状数组】【最近公共祖先】【块状树】bzoj3631 [JLOI2014]松鼠的新家

时间:2015-03-09 14:26:55      阅读:142      评论:0      收藏:0      [点我收藏+]

标签:

裸题,树状数组区间修改+单点查询。当然要稍微讨论一下链的左右端点是否修改的情况咯。

#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define N 300001
int en,v[N<<1],first[N],next[N<<1],n;
void AddEdge(const int &U,const int &V)
{
	v[++en]=V;
	next[en]=first[U];
	first[U]=en;
}
int dep[N],siz[N],fa[N],son[N],top[N],Num[N],tot;
void dfs(int U,int d)
{
    dep[U]=d;
    siz[U]=1;
    for(int i=first[U];i;i=next[i])
      if(v[i]!=fa[U])
        {
          fa[v[i]]=U;
          dfs(v[i],d+1);
          siz[U]+=siz[v[i]];
          if(siz[v[i]]>siz[son[U]])
            son[U]=v[i];
        }
}
void dfs2(int U)
{
    if(son[U])
      {
        top[son[U]]=top[U];
        Num[son[U]]=++tot;
        dfs2(son[U]);
      }
    for(int i=first[U];i;i=next[i])
      if(v[i]!=fa[U]&&v[i]!=son[U])
        {
          top[v[i]]=v[i];
          Num[v[i]]=++tot;
          dfs2(v[i]);
        }
}
int SIZ[N],TOP[N],sz;
void dfs3(int U)
{
    for(int i=first[U];i;i=next[i])
      if(v[i]!=fa[U])
        {
          if(SIZ[TOP[U]]<sz)
            {
              TOP[v[i]]=TOP[U];
              ++SIZ[TOP[U]];
            }
          dfs3(v[i]);
        }
}
int lca(int U,int V)
{
    while(U!=V)
      {
        if(TOP[U]!=TOP[V])
          {
            if(dep[TOP[U]]<dep[TOP[V]])
              swap(U,V);
            U=fa[TOP[U]];
          }
        else
          {
            if(dep[U]<dep[V])
              swap(U,V);
            U=fa[U];
          }
      }
    return U;
}
int d[N];
void add_node(int p,const int &v){for(;p<=n;p+=(p&(-p))) d[p]+=v;}
void add_range(const int &L,const int &R){add_node(L,1);if(R!=n)add_node(R+1,-1);}
int query(int p){int res=0;for(;p;p-=(p&(-p)))res+=d[p];return res;}
void update(int U,int V)
{
	int f1=top[U],f2=top[V];
	while(f1!=f2)
	  {
	  	if(dep[f1]<dep[f2])
	  	  {
	  	  	swap(f1,f2);
	  	  	swap(U,V);
	  	  }
	  	add_range(Num[f1],Num[U]);
	  	U=fa[f1];
	  	f1=top[U];
	  }
	if(dep[U]>dep[V])
	  swap(U,V);
	add_range(Num[U],Num[V]);
}
int cnt,LL[N],RR[N];
void dfs4(int U)
{
	LL[U]=++cnt;
	for(int i=first[U];i;i=next[i])
	  if(v[i]!=fa[U])
	    dfs4(v[i]);
	RR[U]=cnt;
}
int xu[N];
void work(const int &L,const int &R,const int &op)
{
	if(op==n-1)
	  {
	  	if(fa[L]==R||fa[R]==L) return;
	  	int LCA=lca(L,R);
	  	if(LCA==L)
	  	  {
	  	  	for(int i=first[L];i;i=next[i])
	  	  	  if(v[i]!=fa[L]&&LL[R]>=LL[v[i]]&&LL[R]<=RR[v[i]])
	  	    	{
	  	    	  update(v[i],fa[R]);
	  	      	  return;
	  	    	}
	  	  }
	  	else if(LCA==R)
	  	  {
	  	  	for(int i=first[R];i;i=next[i])
	  	  	  if(v[i]!=fa[R]&&LL[L]>=LL[v[i]]&&LL[L]<=RR[v[i]])
	  	    	{
	  	    	  update(fa[L],v[i]);
	  	      	  return;
	  	    	}
	  	  }
	  	else update(fa[L],fa[R]);
	  	return;
	  }
	if(lca(L,R)==L)
	  {
	  	for(int i=first[L];i;i=next[i])
	  	  if(v[i]!=fa[L]&&LL[R]>=LL[v[i]]&&LL[R]<=RR[v[i]])
	  	    {
	  	      update(v[i],R);
	  	      return;
	  	    }
	  }
	else update(fa[L],R);
}
int main()
{
	int A,B;
	scanf("%d",&n);
	for(int i=1;i<=n;++i) scanf("%d",&xu[i]);
	for(int i=1;i<n;++i)
	  {
	  	scanf("%d%d",&A,&B);
	  	AddEdge(A,B);
	  	AddEdge(B,A);
	  }
	top[1]=1;
	Num[1]=++tot;
	dfs(1,1);
	dfs2(1);
	sz=sqrt(n); if(!sz) sz=1;
    for(int i=1;i<=n;i++)
      {
        SIZ[i]=1;
        TOP[i]=i;
      }
    dfs3(1);
	dfs4(1);
	if(n==2)
	  {
	  	work(xu[2],xu[1],0);
	  	goto OUT;
	  }
	update(xu[1],xu[2]);
	for(int i=2;i<n;++i)
	  work(xu[i],xu[i+1],i);
	OUT:for(int i=1;i<=n;++i)
	  printf("%d\n",query(Num[i]));
	return 0;
}

【树链剖分】【树状数组】【最近公共祖先】【块状树】bzoj3631 [JLOI2014]松鼠的新家

标签:

原文地址:http://www.cnblogs.com/autsky-jadek/p/4323411.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!