1. 程式人生 > >洛谷P3258松鼠的新家

洛谷P3258松鼠的新家

tin spa ems 明顯 ring 做了 ont swap fine

  題目傳送門

  恩,很明顯的一個樹剖題,配合樹上差分其實也並不難,不過無奈蒟蒻樹剖還沒那麽熟練,而且樹上差分也做的少,所以這題楞是做了一中午。。。。。。唉,果然我還是太菜了。恩,具體做法在代碼中解釋吧:

  

//It is made by HolseLee on 6th Jan 2018
//luogu.org
#include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #define
ll long long using namespace std; const int N=300030; int n,a[N],c[N],ans[N],head[N],cnt; int sum,hson[N],size[N],fa[N],id; int depth[N],top[N],dfn[N],xu[N]; struct Node{ int to,next; }edge[N<<1]; inline int read()//快讀 { char ch=getchar();int num=0;bool flag=false; while(ch<0||ch>
9){if(ch==-)flag=true;ch=getchar();} while(ch>=0&&ch<=9){num=num*10+ch-0;ch=getchar();} return flag?-num:num; } inline void add(int x,int y)//加邊 { edge[++cnt].to=y; edge[cnt].next=head[x]; head[x]=cnt; }
//兩個dfs,樹剖套路,不解釋 inline
void dfs1(int u) { size[u]=1;
for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].to; if(v==fa[u])continue; depth[v]=depth[u]+1;fa[v]=u; dfs1(v);size[u]+=size[v]; if(!hson[u]||size[v]>size[hson[u]]) hson[u]=v; } } inline void dfs2(int u,int nowtop) { dfn[u]=++id;xu[id]=u;top[u]=nowtop; if(hson[u])dfs2(hson[u],nowtop); for(int i=head[u];i!=-1;i=edge[i].next){ int v=edge[i].to; if(v==fa[u]||v==hson[u])continue; dfs2(v,v);} } inline void lca(int x,int y)//求lca
{
int fax=top[x],fay=top[y]; while(fax!=fay){ if(depth[fax]<depth[fay]) {swap(fax,fay);swap(x,y);} c[dfn[fax]]++;c[dfn[x]+1]--;
   //在深度較淺的點++,較深的點--,差分 x=fa[fax];fax=top[x]; } if(depth[x]<depth[y])swap(x,y); c[dfn[y]]++;c[dfn[x]+1]--;
   //同上 }
void ready() { memset(head,-1,sizeof(head)); n=read(); for(int i=1;i<=n;i++) a[i]=read(); for(int i=1;i<n;i++){ int x=read();int y=read(); add(x,y);add(y,x);}
  //加邊,這裏不需要用a數組
  //從樣例分析就可以知道,加邊的序號是房間原本的編號 depth[
1]=1;fa[1]=0; dfs1(1);dfs2(1,1); } void work() { for(int i=1;i<n;i++){ int x=a[i],y=a[i+1]; lca(x,y);//對每一條路徑的起點終點進行操作 c[dfn[y]]--;c[dfn[y]+1]++; } sum=0; for(int i=1;i<=n;i++){ sum+=c[i]; ans[xu[i]]=sum;
  //記錄結果,這裏註意,不能直接記錄ans[i];
  //要用到xu數組; }
for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
  //輸出,完結
return; } int main() { ready(); work(); return 0; }

  總的來說,這是一道用來練習樹剖和樹上差分的好題。

洛谷P3258松鼠的新家