zoukankan      html  css  js  c++  java
  • bzoj 3631 松鼠的新家 (树链剖分)

    链接: https://www.lydsy.com/JudgeOnline/problem.php?id=3631

    思路:

    直接用树链剖分求每一次运动,因为这道题只需要区间增添,单点求值,没必要用线段树,直接数组标记下就好了

    实现代码

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define lson l,m,rt<<1
    #define rson m+1,r,rt<<1|1
    #define mid int m = (l + r) >> 1
    
    const int M = 1e5 + 10;
    int cnt,cnt1;
    int head[M],dep[M],fa[M],top[M],son[M],siz[M],tid[M],sum[M],a[M];
    
    struct node{
        int to,next;
    }e[M];
    
    void add(int u,int v){
        e[++cnt].to = v;e[cnt].next = head[u];head[u] = cnt;
    }
    
    void dfs1(int u,int faz,int deep){
        dep[u] = deep;
        fa[u] = faz;
        siz[u] = 1;
        for(int i = head[u];i;i=e[i].next){
            int v = e[i].to;
            if(v == fa[u]) continue;
            dfs1(v,u,deep+1);
            siz[u] += siz[v];
            if(siz[v] > siz[son[u]]||son[u] == -1)
                son[u] = v;
        }
    }
    
    void dfs2(int u,int t){
        top[u] = t;
        tid[u] = ++cnt1;
        if(son[u] == -1) return ;
        dfs2(son[u],t);
        for(int i = head[u];i;i=e[i].next){
            int v = e[i].to;
            if(v != fa[u]&&v != son[u])
                dfs2(v,v);
        }
    }
    
    void update(int x,int y){
        sum[x]++;
        sum[y+1]--;
    }
    
    void solve(int x,int y){
        int fx = top[x],fy = top[y];
        int ans = 0;
        while(fx!=fy){
            if(dep[fx] < dep[fy]) swap(x,y),swap(fx,fy);
            update(tid[fx],tid[x]);
            x = fa[fx]; fx = top[x];
        }
        if(dep[x] > dep[y]) swap(x,y);
        update(tid[x],tid[y]);
    }
    
    int main(){
        int n,x,y;
        scanf("%d",&n);
        memset(son,-1,sizeof(son));
        for(int i = 1;i <= n;i ++){
            scanf("%d",&a[i]);
        }
        int n1 = n-1;
        while(n1--){
            scanf("%d%d",&x,&y);
            add(x,y); add(y,x);
        }
        dfs1(1,0,1); dfs2(1,0);
        for(int i = 2;i <= n;i ++)
            solve(a[i-1],a[i]);
        for(int i = 1;i <= n;i ++){
            sum[i] += sum[i-1];
        }
       // cout<<1<<endl;
        for(int i = 1;i <= n;i ++){
            if(i == 1) printf("%d
    ",sum[tid[i]]);
            else printf("%d
    ",sum[tid[i]]-1);
        }
        return 0;
    }
  • 相关阅读:
    RxJava简要分析
    okHttp3源码简要分析
    Android 内存优化浅析
    用暴走漫画写使用手册
    简单的JavaScript互斥锁
    为jQuery添加Webkit的触摸方法支持
    去年做了什么?OA。
    简单地总结下双十一对“老婆”的评价
    麦当劳送薯条活动坑薯条设想,实践被失败
    用.NET MVC实现长轮询,与jQuery.AJAX即时双向通信
  • 原文地址:https://www.cnblogs.com/kls123/p/9806960.html
Copyright © 2011-2022 走看看