树上差分

点差分

例题:松鼠的新家

方法:在两端点+1,他们的lca-1,lca的父亲-1,即可消除影响。

#include<map>
#include<queue>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<deque>
using namespace std;
typedef long long ll;
const int maxm=300007;
int n,p,q;
int a[maxm];
int pre[2*maxm],last[maxm],other[2*maxm],l;
int jump[maxm][21],dep[maxm];
int sum[maxm];
void add(int x,int y)
{
 l++;
 pre[l]=last[x];
 last[x]=l;
 other[l]=y;
}
void dfs(int x)
{
 for(int p=last[x];p;p=pre[p])
 {
  int v=other[p];
  if(v==jump[x][0]) continue;
  jump[v][0]=x;
  dep[v]=dep[x]+1;
  dfs(v);
 }
}
void dfs1(int x)
{
 for(int p=last[x];p;p=pre[p])
 {
  int v=other[p];
  if(v==jump[x][0]) continue;
  dfs1(v);
  sum[x]+=sum[v];
 }	
}
int lca(int x,int y)
{
 if(dep[x]<dep[y]) swap(x,y);
 for(int j=0;j<=19;j++)
 {
  if((dep[x]-dep[y])&(1<<j))
  x=jump[x][j];
 }
 if(x==y) return x;
 for(int j=19;j>=0;j--)
 {
   if(jump[x][j]!=jump[y][j])
   {
     x=jump[x][j];
     y=jump[y][j];
   }
 }
 return jump[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);
  add(x,y);
  add(y,x);
 }
 dfs(1);
 for(int j=1;j<=19;j++)
 {
  for(int i=1;i<=n;i++)
  jump[i][j]=jump[jump[i][j-1]][j-1];
 }
 for(int i=1;i<n;i++)
 {
  int u=a[i],v=a[i+1];
  int lcc=lca(u,v);
  sum[jump[u][0]]++;
  sum[v]++;
  sum[lcc]--;
  sum[jump[lcc][0]]--;
 }
 dfs1(1);
 sum[a[n]]--;
 sum[a[1]]++; 
 for(int i=1;i<=n;i++)
 printf("%d\n",sum[i]);
 return 0;	
}
posted @ 2019-11-06 21:14  lihan123  阅读(110)  评论(0编辑  收藏  举报