bzoj 3631 [JLOI2014]松鼠的新家


題目

傳送門

題解

看到某Yuta的樹總結覺得LCA+樹上差分挺好寫而且差分沒寫過准備水一發結果水了一上午qwq。因為第一次寫樹上差分和樹剖求LCA,結果樹剖版子某處打錯了。。(而且差分點和差分邊還是有一定區別的)。


這題可以用樹剖水部分分,不過n有30w,log方就會被卡了。所以利用差分思想把區間修改轉化為點修改。給每個點一個tag表示新增值(貌似怪怪的)。如果有條路徑(i,j)需要標記那么進行如下操作

tag(i)++;tag(j)++;tag(LCA(i,j))- -;tag(father(LCA(i,j)))- -;

這樣能夠達到標記經過的點的效果,請自行腦補如果是經過的邊如何標記。
那么就把路徑拆分就好了,但是這道題非起始端點會被多算一次(在銜接處),所以統計完后減回來。


題很水,人很蠢。

代碼

//QWsin
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=600000+10;
const int maxm=1200000+10;
inline int read()
{
int ret=0;char ch=getchar();
while(ch<'0'||ch>'9') ch=getchar();
for(;ch>='0'&&ch<='9';ch=getchar()) ret=ret*10+ch-'0';
return ret;
}

int to[maxn];

int first[maxn],next[maxm],ecnt;
struct Edge{int u,v;Edge(int u=0,int v=0):u(u),v(v){}}e[maxm];
inline void add_edge(int u,int v)
{
next[ecnt]=first[u];first[u]=ecnt;e[ecnt++]=Edge(u,v);
next[ecnt]=first[v];first[v]=ecnt;e[ecnt++]=Edge(v,u);
}

int top[maxn],hv[maxn],sz[maxn],p[maxn],dep[maxn];
int tag[maxn];

int dfs1(int u,int fa,int deep=1)
{
p[u]=fa;dep[u]=deep;sz[u]=1;int msz=0;
for(int i=first[u];i!=-1;i=next[i]) if(e[i].v!=fa){
int lch=dfs1(e[i].v,u,deep+1);
if(lch > msz) msz=lch,hv[u]=e[i].v;
sz[u]+=lch;
}
return sz[u];
}

void dfs2(int u,int Top)
{
top[u]=Top;
if(sz[u]==1) return ;
dfs2(hv[u],Top);
for(int i=first[u];i!=-1;i=next[i])
if(e[i].v!=p[u]&&e[i].v!=hv[u]) dfs2(e[i].v,e[i].v);
}

int LCA(int a,int b)
{
for(;top[a]!=top[b];b=p[top[b]])
if(dep[top[a]] > dep[top[b]]) swap(a,b);
return dep[a]<dep[b]?a:b;
}

int ans[maxn],sum,n;
int dfs3(int cur)
{
int sum=tag[cur];
for(int i=first[cur];i!=-1;i=next[i])
if(e[i].v!=p[cur]) sum+=dfs3(e[i].v);
if(to[1]!=cur) ans[cur]=sum-1;
else ans[cur]=sum; return sum;
}

int main()
{
n=read();memset(first,-1,sizeof(first));
for(int i=1;i<=n;i++) to[i]=read();
for(int i=1;i<n;i++) add_edge(read(),read());

int root=1;
dfs1(root,root);dfs2(root,root);

tag[to[1]]++;tag[to[2]]++;
int lca=LCA(to[1],to[2]);
tag[lca]--;if(lca!=root) tag[p[lca]]--;

for(int i=2;i<n;i++)
{
int lca=LCA(to[i],to[i+1]);
tag[to[i]]++;tag[to[i+1]]++;
tag[lca]--;if(lca!=root) tag[p[lca]]--;
}

dfs3(root);
for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
return 0;
}

注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com