• BZOJ3252: 攻略


    题解: 首先 考虑一个贪心策略是 每次选取必然是 每个点到根的路径和的最大值的点 然后考虑去掉这个点的影响 影响子树的价值 这样的话我们就可以dfs序维护子树了 去掉这个点只要把这点的权值在其子树中减去 然后维护到根的最大值和位置 线段树即可 然后顺着根往上爬找到第一个在之前被访问的点即可(因为这个点被访问 他的祖先也必然被访问 做k次得出答案即可

    #include <bits/stdc++.h>
    const int MAXN=2e5+10;
    #define ll long long
    using namespace std;
    struct FastIO
    {
        static const int S=200;
        int wpos;
        char wbuf[S];
        FastIO():wpos(0){}
        inline int xchar()
        {
            static char buf[S];
            static int len=0,pos=0;
            if(pos==len) pos=0,len=fread(buf,1,S,stdin);
            if(pos==len) exit(0);
            return buf[pos++];
        }
        inline int read()
        {
            int s=1,c=xchar(),x=0;
            while(c<=32) c=xchar();
            if(c=='-') s=-1,c=xchar();
            for(;'0'<=c&&c<='9';c=xchar()) x=x*10+c-'0';
            return x*s;
        }
        ~FastIO()
        {
            if(wpos) fwrite(wbuf,1,wpos,stdout),wpos=0;
        }
    }io;
    int n,k;
    int a[MAXN];bool vis[MAXN];
    vector<int>vec[MAXN];
    int fa[MAXN],p[MAXN],fp[MAXN],cnt;
    ll dis[MAXN];int num[MAXN];
    void dfs(int v,int pre){
    	p[v]=++cnt;fp[p[v]]=v;fa[v]=pre;dis[v]=dis[pre]+a[v];num[v]=1;
    	for(int i=0;i<vec[v].size();i++)if(vec[v][i]!=pre){dfs(vec[v][i],v);num[v]+=num[vec[v][i]];}
    }
    ll maxx[MAXN<<2],flag[MAXN<<2];int pos[MAXN<<2];
    void push(int rt){
    	if(flag[rt]!=0){
    		maxx[rt<<1]+=flag[rt];maxx[rt<<1|1]+=flag[rt];
    		flag[rt<<1]+=flag[rt];flag[rt<<1|1]+=flag[rt];
    		flag[rt]=0;
    	}
    }
    void up(int rt){
    	maxx[rt]=maxx[rt<<1];pos[rt]=pos[rt<<1];
    	if(maxx[rt]<maxx[rt<<1|1])maxx[rt]=maxx[rt<<1|1],pos[rt]=pos[rt<<1|1];
    }
    void built(int rt,int l,int r){
    	flag[rt]=0;
    	if(l==r){maxx[rt]=dis[fp[l]];pos[rt]=l;return ;}
    	int mid=(l+r)>>1;
    	built(rt<<1,l,mid);
    	built(rt<<1|1,mid+1,r);
    	up(rt);
    }
    void update(int rt,int l,int r,int ql,int qr,ll vul){
    	if(ql<=l&&r<=qr){maxx[rt]+=vul;flag[rt]+=vul;return ;}
    	int mid=(l+r)>>1;
    	push(rt);
    	if(ql<=mid)update(rt<<1,l,mid,ql,qr,vul);
    	if(qr>mid)update(rt<<1|1,mid+1,r,ql,qr,vul);
    	up(rt);
    }
    int main(){
    	n=io.read();k=io.read();
    	for(int i=1;i<=n;i++)a[i]=io.read();
    	int u,v;
    	for(int i=1;i<n;i++)u=io.read(),v=io.read(),vec[u].push_back(v),vis[v]=1;
    	for(int i=1;i<=n;i++)if(!vis[i]){u=i;break;}
    	for(int i=1;i<=n;i++)vis[i]=0;
    	vis[0]=1;
    	dfs(u,0);built(1,1,n);int cnt=n;
    	ll ans=0;int t1;
    	for(int i=1;i<=k;i++){
    		ans+=maxx[1];t1=fp[pos[1]];
    		while(!vis[t1]&&cnt>0){update(1,1,n,p[t1],p[t1]+num[t1]-1,-a[t1]);vis[t1]=1;cnt--;t1=fa[t1];}
    		if(cnt==0)break;
    	}
    	printf("%lld
    ",ans);
    }
    

    3252: 攻略

    Time Limit: 10 Sec  Memory Limit: 128 MB
    Submit: 967  Solved: 461
    [Submit][Status][Discuss]

    Description

    题目简述:树版[k取方格数]
    众所周知,桂木桂马是攻略之神,开启攻略之神模式后,他可以同时攻略k部游戏。今天他得到了一款新游戏《XX
    半岛》,这款游戏有n个场景(scene),某些场景可以通过不同的选择支到达其他场景。所有场景和选择支构成树状
    结构:开始游戏时在根节点(共通线),叶子节点为结局。每个场景有一个价值,现在桂马开启攻略之神模式,同
    时攻略k次该游戏,问他观赏到的场景的价值和最大是多少(同一场景观看多次是不能重复得到价值的)
    “为什么你还没玩就知道每个场景的价值呢?”
    “我已经看到结局了。”

    Input

    第一行两个正整数n,k
    第二行n个正整数,表示每个场景的价值
    以下n-1行,每行2个整数a,b,表示a场景有个选择支通向b场景(即a是b的父亲)
    保证场景1为根节点
    n<=200000,1<=场景价值<=2^31-1

    Output

    输出一个整数表示答案

    Sample Input

    5 2
    4 3 2 1 1
    1 2
    1 5
    2 3
    2 4

    Sample Output

    10

     

  • 相关阅读:
    Android 数据存储四种方式
    Android 文件系统路径
    Android 修改R包名方法
    Android startActivity 页面跳转
    Android 硬件加速器及其问题小结 gif不显示
    Android 用户界面 ViewGroup(FrameLayout LinearLayout AbsoluteLayout RelativeLayout TableLayout)
    Android 中解决输入法挡住输入框的问题
    Android 调用系统自带应用
    Android onMeasure(widthSpec, heightSpec)
    Android Bitmap Caching Bitmaps(渣翻译)
  • 原文地址:https://www.cnblogs.com/wang9897/p/9484855.html
Copyright © 2020-2023  润新知