洛谷P3258松鼠的新家
阿新 • • 發佈:2018-01-06
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> #definell 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松鼠的新家