zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",ans[i]-(i!=a[1]));
        return 0;
    }
    
  • 相关阅读:
    javascript 拷贝详解
    javascript 递归函数详解
    移动端布局解决方案
    Flexbox
    CSS中越界问题的经典解决方案
    移动应用测试方法与思路
    不是人家太装逼,而是我们太low
    GUI自动化测试策略
    GUI测试稳定性的关键技术
    GUI测试还能这么玩(Page Code Gen + Data Gen + Headless)
  • 原文地址:https://www.cnblogs.com/DUXT/p/5990808.html
Copyright © 2011-2022 走看看