bzoj3631: [JLOI2014]松鼠的新家

思路:首先这道题可以直接裸上树剖。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define maxn 300005
 
int n,tot;
int now[maxn],son[2*maxn],pre[2*maxn],size[maxn],heavy[maxn],dep[maxn],top[maxn];
int dfn[maxn],fa[maxn],ans[maxn],a[maxn],op[maxn],cnt[maxn];
 
inline int read(){
    int x=0;char ch=getchar();
    for (;ch<'0'||ch>'9';ch=getchar());
    for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    return x;
}
 
void add(int a,int b){
    son[++tot]=b;
    pre[tot]=now[a];
    now[a]=tot;
}
 
void link(int a,int b){
    add(a,b),add(b,a);
}
 
void getsize(int x){
    size[x]=1,dep[x]=dep[fa[x]]+1;
    for (int p=now[x];p;p=pre[p])
        if (son[p]!=fa[x]){
            fa[son[p]]=x;
            getsize(son[p]);
            size[x]+=size[son[p]];
            if (size[son[p]]>size[heavy[x]]) heavy[x]=son[p];
        }
}
 
void getdfn(int x){
    top[heavy[x]]=top[x],dfn[heavy[x]]=dfn[x]+1;int cnt=dfn[heavy[x]]+size[heavy[x]];
    for (int p=now[x];p;p=pre[p])
        if (son[p]!=fa[x]){
            if (son[p]!=heavy[x]) dfn[son[p]]=cnt,cnt+=size[son[p]];
            getdfn(son[p]);
        }
}
 
struct segment_tree{
    struct treenode{
        int cover,tag;
    }tree[4*maxn];
    void addtag(int p,int val){
        tree[p].cover+=val;
        tree[p].tag+=val;
    }
    void pushdown(int p){
        if (!tree[p].tag) return;
        addtag(p<<1,tree[p].tag),addtag(p<<1|1,tree[p].tag),tree[p].tag=0;
    }
    void query(int p,int l,int r,int x,int y){
        if (x<=l&&r<=y){
            addtag(p,1);
            return;
        }
        pushdown(p);
        int mid=(l+r)>>1;
        if (x<=mid) query(p<<1,l,mid,x,y);
        if (y>mid) query(p<<1|1,mid+1,r,x,y);
    }
    void getans(int p,int l,int r){
        if (l==r){ans[op[l]]=tree[p].cover;return;}
        pushdown(p);int mid=(l+r)>>1;
        getans(p<<1,l,mid),getans(p<<1|1,mid+1,r);
    }
}T;
 
void query(int x,int y){
    while (top[x]!=top[y]){
        if (dep[top[x]]<dep[top[y]]) swap(x,y);
        T.query(1,1,n,dfn[top[x]],dfn[x]);
        x=fa[top[x]];
    }
    if (dep[x]>dep[y]) swap(x,y);
    T.query(1,1,n,dfn[x],dfn[y]);
}
 
int main(){
    n=read();
    for (int i=1;i<=n;i++) a[i]=read();
    for (int i=2;i<n;i++) cnt[a[i]]++;
    for (int i=1,x,y;i<n;i++) x=read(),y=read(),link(x,y);
    getsize(1);for (int i=1;i<=n;i++) top[i]=i;getdfn(dfn[1]=1);
    for (int i=1;i<=n;i++) op[dfn[i]]=i;
    for (int i=1;i<n;i++) query(a[i],a[i+1]);
    T.getans(1,1,n);
    for (int i=1;i<=n;i++) printf("%d\n",ans[i]-cnt[i]-(i==a[n]));
    return 0;
}

 

然后参见了黄学长的博客发现了一种更为高明的解法,可以在树上差分,令x为路径(u,v)的lca,然后f[u]++,f[v]++,f[x]--,f[fa[x]]--,然后直接一遍dfs累加起来就好了。(为什么我的代码常数辣么大。。。差分被树剖虐。。。。)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
#define maxn 300005
 
int n,tot;
int now[maxn],pre[2*maxn],son[2*maxn],a[maxn],dep[maxn],ans[maxn];
int f[maxn][21];
 
inline int read(){
    int x=0;char ch=getchar();
    for (;ch<'0'||ch>'9';ch=getchar());
    for (;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    return x;
}
 
void add(int a,int b){
    son[++tot]=b;
    pre[tot]=now[a];
    now[a]=tot;
}
 
void link(int a,int b){
    add(a,b),add(b,a);
}
 
void dfs(int x){
    dep[x]=dep[f[x][0]]+1;
    for (int p=now[x];p;p=pre[p])
        if (son[p]!=f[x][0]) f[son[p]][0]=x,dfs(son[p]);
}
 
int lca(int a,int b){
    if (dep[a]<dep[b]) swap(a,b);int x=dep[a]-dep[b],t=0;
    for (;x;x>>=1,t++) if (x&1) a=f[a][t];
    if (a==b) return a;t=log2(dep[a])+1;
    for (;f[a][0]!=f[b][0];){
        for (;f[a][t]==f[b][t];t--);
        a=f[a][t],b=f[b][t];
    }
    return f[a][0];
}
 
void tree_dp(int x){
    for (int p=now[x];p;p=pre[p])
        if (son[p]!=f[x][0]){
            tree_dp(son[p]);
            ans[x]+=ans[son[p]];
        }
}
 
int main(){
    n=read();
    for (int i=1;i<=n;i++) a[i]=read();
    for (int i=1,x,y;i<n;i++) x=read(),y=read(),link(x,y);
    dfs(1);
    for (int i=1;i<=20;i++)
        for (int x=1;x<=n;x++)
            f[x][i]=f[f[x][i-1]][i-1];
    for (int i=1;i<n;i++){
        int x=lca(a[i],a[i+1]);
        ans[a[i]]++,ans[a[i+1]]++,ans[x]--,ans[f[x][0]]--;
    }
    tree_dp(1);
    for (int i=1;i<=n;i++) printf("%d\n",ans[i]-(i!=a[1]));
    return 0;
}

 

posted @ 2016-10-23 20:00  DUXT  阅读(163)  评论(0编辑  收藏  举报