zoukankan      html  css  js  c++  java
  • SPOJ

    题目:https://vjudge.net/contest/307753#problem/I

    题意:有一颗树,上面有白色黑色点,每个点上有一个权值,权值可以为负,现在我要求一条路径,权值和最大,这条路径满足  白色可以随便经过多少个,黑色点的个数必须<=m

    思路:首先又是树上路径题,必然点分治,其实这个题我们在考虑当前子树路径时,我们找前面子树出现过并且黑色出现数<=m-当前黑色节点数 里面出现的最大值这样的一条路径。

    举个栗子:    限制路径黑色数:5

    当前子树下的黑色数 :2  权值  5

    (前面子树出现数)

    黑色数  0   1   2    3    4    5

    权值     1    6   2    4    7    3

    我们就应该在 0-3黑色数里面寻找最大值 ,我们找到了6,所以可以更新最大值为 6+5 

    还有我们对于这条路径黑色数已经超过要求的可以不再搜下去,因为这本身就不符合要求了,下面子树的肯定也不符合。

    所以现在我们的问题转化为如何在前面子树固定黑色数中找到最大值,我们还要记得把当前子树访问完后与前面子树合并,因为一个固定黑色数我们保留最大值即可,其实我们可以把黑色数转化为一个区间,然后区间找最大值,所以我们可以用到树状数组,但是我们非常非常要注意的是->

    !!!注意:因为我们找重心已经是O(n)了,然后我们在重心里面的操作不能是O(n)的,但是我们要清空树状数组要O(n),就成了O(n^2)了,我们要怎么优化呢,>_<,之前我就是没想清楚这里的时间复杂度然后超时了,这里我们只能也是log的,怎么办呢,我们记录下来我们之前操作了哪些点,然后再置0即可,但是树状数组操作的点是以二进制的,这又是第二次犯蠢的地方,我最开始直接把那个路径出现的点去置0了,但是因为树状数组要向上界更新最大值,所以不止更改了这些点,所以要怎么搞呢>_<, 其实就是把记录改的点放在树状数组update操作里面即可,我真的傻了>_<

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<iostream> 
    #include<vector>
    #include<queue>
    #define maxn 200005
    #define mod 0x3f3f3f3f
    using namespace std;
    typedef long long ll;
    ll da;
    vector<pair<ll,ll> > mp[maxn],xx[maxn];//存下图 
    pair<ll,ll> e[maxn];
    ll e2[20*maxn];
    bool vis[maxn];//标记曾经使用过的重心 
    ll maxsize[maxn],dis[maxn],d[maxn],flag[maxn],yj[maxn];//maxsize 当前节点的最大子树 
    ll siz[maxn],xd[maxn];// dis 到重心的距离  d 出现过的距离 
    ll n,m,k,rt,sum,qe,qe2,ans1,ans2;  // siz 当前节点的子树个数  e 出现的距离  rt代表当前重心 
    void find(ll x,ll f){//找出重心 
        siz[x]=1;
        maxsize[x]=0;
        for(int i=0;i<mp[x].size();i++){
            pair<ll,ll> q=mp[x][i];
            if(q.first==f||vis[q.first]) continue;//vis数组标记曾经使用过的重心 
            find(q.first,x);
            siz[x]+=siz[q.first];
            maxsize[x]=max(maxsize[x],siz[q.first]); 
        } 
        maxsize[x]=max(maxsize[x],sum-siz[x]);//节点总数减去当前的子树数=以当前节点为根的父亲点子树数 
        if(maxsize[x]<maxsize[rt]){
            rt=x;
        } 
    }
    void query(ll z,ll sm){
        if(z>ans1){
            ans1=z;
            ans2=sm;
        }
        else if(z==ans1){
            ans2+=sm;
        }
    }
    ll lowbit(ll x){
        return x&(-x);
    }
    void update(ll x,ll y){
        while(x<=m){
            e2[qe2++]=x;
            flag[x]=max(flag[x],y);
            x+=lowbit(x);
        }
    }
    ll query(ll x){
        ll ans=0;
        while(x){
            ans=max(ans,flag[x]);
            x-=lowbit(x);
        }
        return ans;
    } 
    void get_dis(ll x,ll f,ll len,ll yjs,ll root){
        
        if(yjs<=m) ans1=max(ans1,len);
        else return; 
        
        ll t=m-yjs;
        if(yj[root]) t++;
        ans1=max(ans1,len+query(t+1));
        e[qe].first=yjs;
        e[qe].second=len;
        qe++;
        for(int i=0;i<mp[x].size();i++){
            pair<ll,ll> q=mp[x][i];
            if(q.first==f||vis[q.first]) continue;
            //dis[q.first]=(dis[x]+len)%3;
            get_dis(q.first,x,len+q.second,yjs+yj[q.first],root);
        }    
    }
    void divide(ll x){
        vis[x]=1;
        //printf("rt=%lld ans1=%lld
    ",x,ans1);
        for(int i=0;i<mp[x].size();i++){
            pair<ll,ll> q=mp[x][i];
            qe=0;
            if(vis[q.first]) continue;
            //dis[x]=q.second;
            get_dis(q.first,x,q.second,yj[x]+yj[q.first],x);
            for(int j=0;j<qe;j++){
                update(e[j].first+1,e[j].second);
            }
        }
        for(int i=0;i<qe2;i++){
            flag[e2[i]]=0;
        }
        qe2=0;
        for(int i=0;i<mp[x].size();i++){
            pair<ll,ll> q=mp[x][i];
            if(vis[q.first]) continue;
            //if(da>0) break;
            sum=siz[q.first];
            rt=0;
            maxsize[rt]=mod;
            find(q.first,x);
            divide(rt);
        }
    //    vis[x]=0;
    }
    void init(){
        ans1=0;ans2=0;
        for(int i=0;i<=n+1;i++) mp[i].clear();
        for(int i=0;i<=n+1;i++) vis[i]=0;
        for(int i=0;i<=n+1;i++) flag[i]=0;
        for(int i=0;i<=n+1;i++) yj[i]=0;
    } 
    int main(){
        ll t;
        while(scanf("%lld%lld%lld",&n,&m,&k)!=EOF){
            ll a,b,c;
            init();
            ll xx;
            for(int i=1;i<=k;i++){
                scanf("%lld",&xx);
                yj[xx]=1;
            }
            for(int i=1;i<=n-1;i++){
                scanf("%lld%lld%lld",&a,&b,&c);
                mp[a].push_back(make_pair(b,c));
                mp[b].push_back(make_pair(a,c)); 
            }
            sum=n;//当前节点数 
            rt=0;
            maxsize[0]=mod;//置初值 
            find(1,0);
            divide(rt);
            printf("%lld
    ",ans1);
        }
    } 
  • 相关阅读:
    C#使用表达式树实现对象复制
    用vbs将字符串复制到剪贴板
    C# 动态获取程序集信息
    关于ftp的主动模式(Active Mode)和被动模式(Passive Mode)
    %userprofile%\Local Settings文件夹拒绝访问怎么办
    在Winform框架的多文档界面中实现双击子窗口单独弹出或拖出及拽回的处理
    ABP VNext框架基础知识介绍(1)框架基础类继承关系
    ABP开发框架中分页查询排序的实现处理
    Vue&Element开发框架中增加工作流处理,工作流的各个管理页面的界面处理
    基于ABP开发框架的技术点分析和项目快速开发实现
  • 原文地址:https://www.cnblogs.com/Lis-/p/11368452.html
Copyright © 2011-2022 走看看