bzoj 3631 松鼠的新家

自己乱搞了一个线段树维护dfs序,结果卡着内存过了。

dfs序维护的是子节点和父节点的关系,并不是路径上的关系。

然而膜拜题解发现只要在倍增lca的时候打上标记就可以了。不会On求lca,先挖一个坑

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>

#define md
#define ll long long
#define inf (int) 1e9
#define eps 1e-8
#define N 600010
#define M 4*N
using namespace std;
struct yts { int x,t,ne;} e[2*N];
int left[N],right[N],opt[N],v[N],a[N],fa[N][25],dep[N];
int cheng[M],ad[M],dt[M];
int dfs_cnt=0,num=0,n;
void put(int x,int y)
{
 num++; e[num].x=x; e[num].t=y;
 e[num].ne=v[x]; v[x]=num;
}
void dfs(int x)
{
 left[x]=++dfs_cnt; opt[dfs_cnt]=1;
 for (int i=v[x];i;i=e[i].ne)
 {
  int y=e[i].t;
  if (!left[y])
  {
   fa[y][0]=x; dep[y]=dep[x]+1;
   dfs(y);
  }
 }
 right[x]=++dfs_cnt; opt[dfs_cnt]=-1;
}
void build(int i,int l,int r)
{
 cheng[i]=ad[i]=0;
 if (l==r) { dt[i]=opt[l]; return;}
 int mid=(l+r)>>1;
 build(2*i,l,mid); build(2*i+1,mid+1,r);
 dt[i]=dt[2*i]+dt[2*i+1];
}
void release(int i)
{
 int l=2*i,r=2*i+1;
 if (ad[i]!=0)
 {
  ad[l]+=ad[i]; ad[r]+=ad[i];
  cheng[l]+=ad[i]; cheng[r]+=ad[i];
  ad[i]=0;
 }
}
void modify(int i,int l,int r,int d,int ln,int rn)
{
 if (l<=ln&&rn<=r) { ad[i]+=d; cheng[i]+=d; return;}
 release(i);
 int mid=(ln+rn)>>1;
 if(l<=mid) modify(2*i,l,r,d,ln,mid);
 if (mid+1<=r) modify(2*i+1,l,r,d,mid+1,rn);
}
int query(int i,int x,int ln,int rn)
{
 if (ln==rn) return cheng[i]*dt[i];
 release(i);
 int mid=(ln+rn)>>1;
 if (x<=mid) return query(2*i,x,ln,mid); else return query(2*i+1,x,mid+1,rn);
}
void build_lca()
{
 for (int j=1;j<=20;j++)
  for (int i=1;i<=n;i++)
  {
   if (fa[i][j-1]) fa[i][j]=fa[fa[i][j-1]][j-1];
  }
}
int lca(int x,int y)
{
 if (dep[x]<dep[y]) swap(x,y);
 int t=dep[x]-dep[y];
 for (int i=20;i>=0;i--) if (t&(1<<i)) x=fa[x][i];
 if (x==y) return x;
 for (int i=20;i>=0;i--)
   if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
 return fa[x][0];
}
 
int main()
{
 scanf("%d",&n);
 for (int i=1;i<=n;i++) scanf("%d",&a[i]);
 for (int i=1;i<=n-1;i++)
 {
  int x,y;
  scanf("%d%d",&x,&y);
  put(x,y); put(y,x);
 }
 dep[1]=1; dfs(1); build_lca();
 //for (int i=1;i<=n;i++) printf("lr %d %d\n",left[i],right[i]);
 build(1,1,dfs_cnt);
 for (int i=2;i<=n;i++)
 {
  int x=a[i-1],y=a[i];
  int z=lca(x,y);
  if (z!=x&&z!=y) { modify(1,left[z],left[x],1,1,dfs_cnt); modify(1,left[z],left[y],1,1,dfs_cnt); modify(1,left[z],left[z],-1,1,dfs_cnt);}
  else
  {
   if (left[x]>left[y]) swap(x,y);
   modify(1,left[x],left[y],1,1,dfs_cnt);
  }
  //printf("mo: %d %d\n",x,y);
 }
 for (int i=1;i<=n;i++)
 {
  int ans=query(1,left[i],1,dfs_cnt)+query(1,right[i],1,dfs_cnt);
  if (a[1]==i) printf("%d\n",ans); else printf("%d\n",ans-1);
 }
 return 0;
}


你可能感兴趣的:(bzoj 3631 松鼠的新家)