zoukankan      html  css  js  c++  java
  • BZOJ 4860: [BeiJing2017]树的难题 点分治+线段树

    这个思路还是非常巧妙的. 

    困难在于我们需要同时维护以 $x$ 为分治中心,延伸出颜色相同/不同的最大值.      

    不同的话直接将权和相加,相同的话还需要减掉重复部分,这就比较难办.  

    但是我们发现,当以 $x$ 为分治中心时,$x$ 每一个儿子为根的子树的延伸颜色都是相同的. 

    所以我们可以将每一个点的所有儿子按照延伸颜色排序,然后维护两颗线段树:相同与不同. 

    当我们在点分治时处理到下一个儿子,而下一个儿子与当前儿子颜色不同时,用线段树合并的方式将相同线段树合并到不同即可. 

    code:

    #include <cstdio> 
    #include <string>  
    #include <vector>
    #include <cstring> 
    #include <algorithm>   
    #define N 200006 
    #define ll long long  
    #define inf 1000000009 
    using namespace std; 
    void setIO(string s) 
    {
        freopen((s+".in").c_str(),"r",stdin);  
        // freopen((s+".out").c_str(),"w",stdout);  
    }
    int answer=-inf,mp=0; 
    namespace seg
    {   
        int tot;     
        struct node { int ls,rs,maxx; }s[N*50];      
        void clr()  
        { 
            for(int i=1;i<=tot;++i) s[i].ls=s[i].rs=0,s[i].maxx=-inf;   
            tot=0;  
        }     
        int merge(int x,int y) 
        {                               
            if(!x||!y) return x+y;     
            s[x].maxx=max(s[x].maxx,s[y].maxx);    
            s[x].ls=merge(s[x].ls,s[y].ls); 
            s[x].rs=merge(s[x].rs,s[y].rs);   
            return x;  
        }
        void update(int &x,int l,int r,int p,int v) 
        {
            if(!x) x=++tot,s[x].maxx=-inf;    
            s[x].maxx=max(s[x].maxx,v); 
            if(l==r) return;  
            int mid=(l+r)>>1;   
            if(p<=mid)  update(s[x].ls,l,mid,p,v); 
            else update(s[x].rs,mid+1,r,p,v);   
        }       
        int query(int x,int l,int r,int L,int R) 
        {
            if(!x||L>R) return -inf; 
            if(l>=L&&r<=R) return s[x].maxx;  
            int mid=(l+r)>>1,re=-inf;  
            if(L<=mid) re=max(re,query(s[x].ls,l,mid,L,R)); 
            if(R>mid)  re=max(re,query(s[x].rs,mid+1,r,L,R));     
            return re;   
        }
    };  
    int n,m,_min,_max,root,sn,tot;       
    int val[N],size[N],mx[N],vis[N];     
    struct Edge 
    {
        int to,w;    
        Edge(int to=0,int w=0):to(to),w(w){}  
    };  
    struct Dis 
    { 
        int d,v; 
        Dis(int d=0,int v=0):d(d),v(v){}  
    }A[N];  
    vector<Edge>F[N];  
    vector<Edge>G[N];  
    bool cmp(Edge a,Edge b) { return a.w<b.w; }   
    void getroot(int u,int ff) 
    {      
        size[u]=1,mx[u]=0; 
        for(int i=0;i<G[u].size();++i) 
        {
            int v=G[u][i].to;   
            if(vis[v]||v==ff)  continue;       
            getroot(v,u),size[u]+=size[v];   
            mx[u]=max(mx[u],size[v]);                                 
        }
        mx[u]=max(mx[u],sn-size[u]); 
        if(mx[u]<mx[root]) root=u;  
    } 
    void dfs(int u,int ff,int d,int v,int pr) 
    {     
        A[++tot]=Dis(d,v);             
        for(int i=0;i<G[u].size();++i) 
        {
            int y=G[u][i].to; 
            if(vis[y]||y==ff) continue;     
            dfs(y,u,d+1,v+val[G[u][i].w]*(G[u][i].w!=pr),G[u][i].w);                                        
        }
    }
    void solve(int u) 
    {       
        int rt_diff=0,rt_same=0;    
        F[u].clear();  
        for(int i=0;i<G[u].size();++i) if(!vis[G[u][i].to]) F[u].push_back(G[u][i]);   
        for(int i=0;i<F[u].size();++i) 
        {
            int v=F[u][i].to;          
            tot=0; 
            dfs(v,u,1,val[F[u][i].w],F[u][i].w);                       
            for(int j=1;j<=tot;++j) 
            {   
                if(A[j].d>_max)  continue;     
                if(A[j].d>=_min&&A[j].d<=_max) 
                {    
                    answer=max(answer,A[j].v),mp=max(mp,A[j].v);      
                }
                answer=max(answer,A[j].v+seg::query(rt_diff,1,n,max(1,_min-A[j].d),_max-A[j].d));       
                answer=max(answer,A[j].v+seg::query(rt_same,1,n,max(1,_min-A[j].d),_max-A[j].d)-val[F[u][i].w]);   
            }
            for(int j=1;j<=tot;++j) seg::update(rt_same,1,n,A[j].d,A[j].v);    
            if(i<F[u].size()-1&&F[u][i+1].w!=F[u][i].w)  
            {
                rt_diff=seg::merge(rt_diff,rt_same); 
                rt_same=0;  
            }                        
        }   
        seg::clr();              
        vis[u]=1;   
        for(int i=0;i<F[u].size();++i) 
        {
            int v=F[u][i].to;     
            sn=size[v],root=0,getroot(v,u),solve(root);  
        }
    }
    int main() 
    { 
        // setIO("input");  
        int i,j;   
        scanf("%d%d%d%d",&n,&m,&_min,&_max);   
        for(i=1;i<=m;++i)  scanf("%d",&val[i]);     
        for(i=1;i<n;++i) 
        {
            int x,y,z; 
            scanf("%d%d%d",&x,&y,&z);   
            G[x].push_back(Edge(y,z));   
            G[y].push_back(Edge(x,z));  
        }
        for(i=1;i<=n;++i) sort(G[i].begin(),G[i].end(),cmp);                  
        sn=n,mx[root=0]=N,getroot(1,0),solve(root),printf("%d
    ",answer); 
        return 0; 
    }
    

      

  • 相关阅读:
    IOS整体代码复习一
    IOS复习UIActionSheet&UIAlertView
    IOS复习Plist文件的读取和写入
    IOS复习UITextfield&UILabel
    iOS中判断两个圆是否重叠
    iOS指针回调函数
    ios函数指针
    iOS分区
    ios指针第二天
    iOS指针第一天
  • 原文地址:https://www.cnblogs.com/guangheli/p/12124513.html
Copyright © 2011-2022 走看看