zoukankan      html  css  js  c++  java
  • hihoCoder #1381 : Little Y's Tree

    http://hihocoder.com/problemset/problem/1381

    一个结论:集合A的直径为a--b,集合B的直径为c--d,那么集合A∪B的直径必是以下6种之一:

    a--b  c--d  a--c  a--d  b--c  b--d

    断掉一条边,相当于从树的dfs序上取出一段区间

    用线段树维护dfs序上任意一段区间的直径

    如果[1,10]断掉的是[1,4] [3,4] [7,8]

    答案就是[1,2]的直径+[3,4]的直径+[5,6]∪[9,10]的直径+[7,8]的直径

    #include<cstdio>
    #include<vector>
    #include<iostream>
    #include<algorithm>
    
    using namespace std;
    
    #define N 100001
    typedef long long LL;
    
    int n;
    int tot,front[N],nxt[N<<1],to[N<<1],val[N<<1];
    
    int lo2[N];
    
    int dep[N],dy[N],fa[N][18];
    LL dis[N];
    int ll[N],rr[N];
    
    vector<int>inc[N];
    int st[N],top;
    
    int a[N],bin[N],cnt;
    LL ans;
    
    struct node
    {
        int a,b;
        LL dis;
    }tr[N<<2];
    
    void read(int &x)
    {
        x=0; char c=getchar();
        while(!isdigit(c)) c=getchar();
        while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    }
    
    void add(int u,int v,int w)
    {
        to[++tot]=v; nxt[tot]=front[u]; front[u]=tot; val[tot]=w;
        to[++tot]=u; nxt[tot]=front[v]; front[v]=tot; val[tot]=w;
    }
    
    void init()
    {
        read(n);
        int u,v,w;
        for(int i=1;i<n;++i)
        {
            read(u); read(v); read(w);
            add(u,v,w);
        }
    }
    
    void dfs(int x)
    {
        ll[x]=++tot;
        dy[tot]=x;
        int t;
        for(int i=front[x];i;i=nxt[i])
        {
            t=to[i];
            if(fa[t][0]) continue;
            fa[t][0]=x;
            dis[t]=dis[x]+val[i];
            dep[t]=dep[x]+1;
            dfs(t);
        }
        rr[x]=tot;
    }
    
    void pre()
    {
        for(int i=2;i<=n;++i) lo2[i]=lo2[i>>1]+1; 
        fa[1][0]=-1;
        tot=0;
        dfs(1);
        int m=lo2[n]; 
        fa[1][0]=0; 
        for(int i=1;i<=n;++i)
            for(int j=1;j<=m;++j)
                fa[i][j]=fa[fa[i][j-1]][j-1];
                
    }
    
    int getlca(int x,int y)
    {
        int m=lo2[dep[x]];
        for(int i=m;i>=0;--i)
            if(ll[fa[x][i]]>ll[y]) x=fa[x][i];
        return fa[x][0];
    }
    
    LL getdis(int x,int y)
    {
        x=dy[x];
        y=dy[y];
        if(x==y) return 0;
        if(ll[x]<ll[y]) swap(x,y);
        int lca=getlca(x,y);
        if(lca==y) return dis[x]-dis[y];
        return dis[x]+dis[y]-dis[lca]*2;
    }
    
    node unionn(node p,node q)
    {
        node t1=(node){p.a,q.a,getdis(p.a,q.a)};
        node t2=(node){p.a,q.b,getdis(p.a,q.b)};
        node t3=(node){p.b,q.a,getdis(p.b,q.a)};
        node t4=(node){p.b,q.b,getdis(p.b,q.b)};
        node t=p;
        if(q.dis>t.dis) t=q;
        if(t1.dis>t.dis) t=t1;
        if(t2.dis>t.dis) t=t2;
        if(t3.dis>t.dis) t=t3;
        if(t4.dis>t.dis) t=t4;
        return t;    
    }
    
    void build(int k,int l,int r)
    {
        if(l==r)
        {
            tr[k].a=tr[k].b=l;
            return;
        }
        int mid=l+r>>1;
        build(k<<1,l,mid);
        build(k<<1|1,mid+1,r);
        tr[k]=unionn(tr[k<<1],tr[k<<1|1]);
    }
    
    bool cmp(int p,int q)
    {
        return ll[p]<ll[q];
    }
    
    node query(int k,int l,int r,int opl,int opr)
    {
        if(l>=opl && r<=opr) return tr[k];
        int mid=l+r>>1;
        if(opr<=mid) return query(k<<1,l,mid,opl,opr);
        if(opl>mid) return query(k<<1|1,mid+1,r,opl,opr);
        node tmp1=query(k<<1,l,mid,opl,opr);
        node tmp2=query(k<<1|1,mid+1,r,opl,opr);
        return unionn(tmp1,tmp2);    
    }
    
    void dfs2(int x)
    {
        int l=ll[x],m=inc[x].size(),t;
        node tmp,mx;
        mx.a=mx.b=ll[x];
        mx.dis=0;
        for(int i=0;i<m;++i)
        {
            t=inc[x][i];
            if(ll[t]!=l)
            {
                tmp=query(1,1,n,l,ll[t]-1);
                mx=unionn(mx,tmp);
            }
            dfs2(t);
            l=rr[t]+1;
        }
        if(l!=rr[x]+1) 
        {
            tmp=query(1,1,n,l,rr[x]);
            mx=unionn(mx,tmp);
        }
        ans+=mx.dis;    
    }
    
    void solve()
    {
        int m,k,x,y;
        read(m);
        while(m--)
        {
            for(int i=1;i<=cnt;++i) inc[bin[i]].clear();
            cnt=ans=0;
            st[top=1]=1;
            read(k);
            for(int i=1;i<=k;++i) 
            {
                read(x);
                x<<=1;
                if(ll[to[x]]<ll[to[x-1]]) y=to[x-1];
                else y=to[x];
                a[i]=y;
            }
            sort(a+1,a+k+1,cmp);
            for(int i=1;i<=k;++i)
            {
                y=a[i];
                while(!(ll[y]>=ll[st[top]] && rr[y]<=rr[st[top]])) top--;
                inc[st[top]].push_back(y);
                bin[++cnt]=st[top];
                st[++top]=y; 
            }
            dfs2(1);
            cout<<ans<<'
    ';
        }
    }
    
    int main()
    {
        init();
        pre();
        build(1,1,n);
        solve();
    } 
    时间限制:24000ms
    单点时限:4000ms
    内存限制:512MB

    描述

    小Y有一棵n个节点的树,每条边都有正的边权。

    小J有q个询问,每次小J会删掉这个树中的k条边,这棵树被分成k+1个连通块。小J想知道每个连通块中最远点对距离的和。

    这里的询问是互相独立的,即每次都是在小Y的原树上进行操作。

    输入

    第一行一个整数n,接下来n-1行每行三个整数u,v,w,其中第i行表示第i条边边权为wi,连接了ui,vi两点。

    接下来一行一个整数q,表示有q组询问。

    对于每组询问,第一行一个正整数k,接下来一行k个不同的1到n-1之间的整数,表示删除的边的编号。

    1<=n,q,Σk<=105, 1<=w<=109

    输出

    共q行,每行一个整数表示询问的答案。

    样例输入
    5
    1 2 2
    2 3 3
    2 4 4
    4 5 2
    3
    4 1 2 3 4
    1 4
    2 2 3
    样例输出
    0
    7
    4
  • 相关阅读:
    知识:CSS 词汇表(中英对照)_CSS Vocabulary
    js基础学习笔记(三)
    js基础学习笔记(二)
    js基础学习笔记(一)
    自己写的一个分页控件类(WinForm)
    JS判断浏览器是否支持某一个CSS3属性
    JavaScript用JQuery呼叫Server端方法
    ASP.NET MVC中的Json Binding和Validate
    ASP.NET Web Forms的改进
    8 种提升ASP.NET Web API性能的方法
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/11881432.html
Copyright © 2011-2022 走看看