• bzoj1103: [POI2007]大都市meg


    dfs序。

    用l[u]和r[u]表示进入u和出去u的时间。用树状数组维护前缀和,l[u]处加1,r[u]处减1。

    询问的是树根到自己u的距离,就相当于l[u]处的前缀和。为什么呢?

    如果一个节点v在树根到u的路径上,就会在l[v]处加1。如果不在,如果编号小于u,l[v]和r[v]处相消。

    如果大于u则l[v]大于l[u]。W u操作则是将l[u]处减1,将r[u]处加1。这样u就不会影响路径长度了。

    dfs序的巧妙应用。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    const int maxn = 250000 + 10;
    const int maxm = 500000 + 10;
    
    struct BIT {
        int a[maxn<<1],n;
        
        inline int lowbit(int x) {
            return (x&(-x));
        }
        
        void add(int x,int v) {
            for(;x<=n;x+=lowbit(x))
                a[x]+=v;    
        }
        
        int sum(int x) {
            int res=0;
            for(;x;x-=lowbit(x)) res+=a[x];
            return res;
        }
        
        void init(int m) {
            memset(a,0,sizeof(a));
            n=m;
        }
        
    } bit;
    
    int g[maxn],v[maxm],next[maxm],eid;
    int fa[maxn],l[maxn],r[maxn],s[maxn],sp,dfn;
    int n,m;
    
    
    void addedge(int a,int b) {
        v[eid]=b; next[eid]=g[a]; g[a]=eid++;
        v[eid]=a; next[eid]=g[b]; g[b]=eid++;
    }
    
    void dfs() {
        s[++sp]=1;
        
        while(sp) {
            int u=s[sp--];
            if(!l[u]) {
                l[u]=++dfn;
                s[++sp]=u;
                for(int i=g[u];~i;i=next[i]) if(v[i]!=fa[u]) {
                    fa[v[i]]=u; 
                    s[++sp]=v[i];
                }
            }
            else r[u]=++dfn;
        }
    }
    
    int main() {
        scanf("%d",&n);
        memset(g,-1,sizeof(g));
        bit.init(n*2);
        for(int i=1,a,b;i<n;i++) {
            scanf("%d%d",&a,&b);
            addedge(a,b);
        }
        dfs();
        
        for(int i=2;i<=n;i++) {
            bit.add(l[i],1);
            bit.add(r[i],-1);    
        }
        char op[10];
        scanf("%d",&m); m+=(n-1);
        for(int    i=1,a,b;i<=m;i++) {
            scanf("%s%d",s,&a);
            if(s[0]=='A') {
                scanf("%d",&b);
                if(a>b) swap(a,b);
                bit.add(l[b],-1);
                bit.add(r[b],1);    
            }
            else printf("%d
    ",bit.sum(l[a]));
        }
        return 0;    
    }
  • 相关阅读:
    第十四周学习进度
    二阶段冲刺(七)
    二阶段冲刺(六)
    二阶段冲刺(五)
    二阶段冲刺(四)
    二阶段冲刺(三)
    二阶段冲刺(二)
    二阶段冲刺(一)
    第十三周学习进度
    linux初级学习笔记二:linux操作系统及常用命令,文件的创建与删除和命名规则,命令行展开以及linux中部分目录的作用!(视频序号:02_3)
  • 原文地址:https://www.cnblogs.com/invoid/p/5478738.html
Copyright © 2020-2023  润新知