【BZOJ3631】【JLOI2014】松鼠的新家

原题传送门

题意:给你一棵树,然后有一个遍历顺序,你需要补全这个遍历顺序,然后输出这个遍历顺序中每个点的出现次数。

解题思路:本来想找树剖的题,结果发现了一题可以直接写lca的。。。。

做法1:非常简单的NOIP式做法就是tjlca后直接树上差分即可。时间效率\( O(n) \)(常数较大).(BZOJ上1064ms)

#include <stdio.h>
#include <string.h>
#define MN 300005
#define v edge[i].to
struct link{int to,nxt;}edge[MN<<4];
int cf[MN],h[MN],q[MN],a[MN],n,cnt,lca[MN],fa[MN],f[MN];
inline int in(){
    int x=0;bool f=0; char ch=getchar();
    while(ch<'0'||ch>'9') f=ch=='-',ch=getchar();
    while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return f?-x:x;
}
inline void ins(int *h,int x,int y){edge[++cnt].to=y,edge[cnt].nxt=h[x],h[x]=cnt;}
inline void insw(int x,int y){ins(h,x,y);ins(h,y,x);}
inline int getfa(int x){return fa[x]?fa[x]=getfa(fa[x]):x;}
inline void tjlca(int u){
    for (register int i=h[u]; i; i=edge[i].nxt)
        if (v!=f[u]) f[v]=u,tjlca(v),fa[v]=u;
    for (register int i=q[u]; i; i=edge[i].nxt)
        if (lca[v]) lca[v]=getfa(lca[v]);
        else lca[v]=u;
}
inline void dfs(int u){
    for (register int i=h[u]; i; i=edge[i].nxt)
        if (v!=f[u]) dfs(v),cf[u]+=cf[v];
}
void init(){
    n=in();for (int i=1; i<=n; ++i) a[i]=in(),ins(q,a[i],i),ins(q,a[i],i-1);
    for (register int i=1; i<n; ++i) insw(in(),in());
}
void solve(){
    tjlca(1);for (register int i=1; i<n; ++i)
        ++cf[a[i]],++cf[a[i+1]],--cf[lca[i]],--cf[f[lca[i]]];dfs(1);
    for (register int i=2; i<=n; ++i) --cf[a[i]];
    for (register int i=1; i<=n; ++i) printf("%d\n",cf[i]);
}
int main(){init(); solve(); return 0;}

做法2:用树剖代替lca,用差分序列维护剖下来的树,也可以直接AC。时间效率为\( O(n \log \log n)\) ~\(O(n \log n) \)。(BZOJ 792ms)

#include <stdio.h>
#define MN 300005
int cnt,to[MN<<1],nxt[MN<<1];
int head[MN],siz[MN],son[MN],dep[MN],a[MN],top[MN],fa[MN],pos[MN],n,d[MN],dfsn;
inline int in(){
    int x=0;bool f=0; char ch=getchar();
    while(ch<'0'||ch>'9') f=ch=='-',ch=getchar();
    while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    return f?-x:x;
}
inline void ins(int x,int y){to[++cnt]=y,nxt[cnt]=head[x],head[x]=cnt;}
inline void insw(int x,int y){ins(x,y);ins(y,x);};
inline void swp(int &a,int &b){a^=b^=a^=b;}
inline void dfs1(int u,int f,int d){
    siz[u]=1,fa[u]=f,dep[u]=d;
    for (register int i=head[u]; i; i=nxt[i])
        if (to[i]!=f){
            dfs1(to[i],u,d+1);siz[u]+=siz[to[i]];
            if (siz[to[i]]>siz[son[u]]) son[u]=to[i];
        }
}
inline void dfs2(int u,int tp){
    top[u]=tp,pos[u]=(++dfsn);if (son[u]) dfs2(son[u],tp);
    for (register int i=head[u]; i; i=nxt[i])
        if (to[i]!=fa[u]&&to[i]!=son[u]) dfs2(to[i],to[i]);
}
inline void update(int x,int y){
    while(top[x]!=top[y]){
        if (dep[top[x]]<dep[top[y]]) swp(x,y);
        ++d[pos[top[x]]],--d[pos[x]+1];x=fa[top[x]];
    }if (dep[x]>dep[y]) swp(x,y);++d[pos[x]],--d[pos[y]+1];
}
void init(){
    n=in();for (register int i=1; i<=n; ++i) a[i]=in();
    for (register int i=1; i<n; ++i) insw(in(),in());
    dfs1(1,1,1);dfs2(1,1);
}
void solve(){
    for (register int i=1; i<n; ++i) {
        update(a[i],a[i+1]);    
        if (i!=1) --d[pos[a[i]]],++d[pos[a[i]]+1];
    }--d[pos[a[n]]],++d[pos[a[n]]+1];
    for (register int i=1; i<=n; ++i) d[i]+=d[i-1];
    for (register int i=1; i<=n; ++i)
        printf("%d\n",d[pos[i]]);
}
int main(){init(); solve(); return 0;}

 

posted @ 2017-04-28 09:54  Melacau  阅读(228)  评论(0编辑  收藏  举报