zoukankan      html  css  js  c++  java
  • 「解题报告」[luoguP6584]重拳出击 (贪心).md

    「解题报告」[luoguP6584]重拳出击 (贪心).md

    传送门

    题面

    题意

    有一颗大小为 (n) 的边权为 (1) 的无根树, 树上有 (m) 个 Youyou.

    初始时, 小 Z 在 (x) 号节点上.

    每一回合, 小 Z 可以杀死所有与它距离小于等于 (k) 的 Youyou, 并可以移动到相邻节点或保持不动.

    回合结束时, 所有的 Youyou 会向小 Z 的方向移动一条边, 若它与小 Z 在同一节点上, 则不移动.

    求小 Z 消灭所有的 Youyou 所需的最小回合数.

    数据范围

    (1 le n,m le 4 imes 10^5, 0 le k le 10^6).


    思路

    以小 Z 初始位置 x 为根节点

    找出深度最深的 Youyou, 记为 y, 记它的深度为 dis. 可以证明 : 处理完 y 后再回到根节点, 所需的天数为 dis. (对 dis 分奇偶讨论一下就能证).

    而 dis 天后, 剩余的 Youyou 肯定会与小 Z 相遇. (否则它的深度就大于 dis.)

    所以先处理 y 后再处理剩下的 Youyou 可能不会比在根节点等着更劣.

    具体做法 : 遍历从 x 到 y 的这条链, 对每个节点算出 "处理完 y 后再去处理它子树中深度次大的点" 的时间, 取个 max, 最后答案即为 "处理 y 所需的时间" +max.


    代码

    #include<bits/stdc++.h>
    using namespace std;
    const int _=4e5+7,__=8e5+7,inf=0x3f3f3f3f;
    int n,m,X,K,ans,maxn,dis[_],pl;
    int lst[_],nxt[__],to[__],tot;
    bool b[_],tag;
    void _add(int x,int y){
        nxt[++tot]=lst[x]; to[tot]=y; lst[x]=tot;
        nxt[++tot]=lst[y]; to[tot]=x; lst[y]=tot;
    }
    void _init(){
        cin>>n; int x,y;
        for(int i=1;i<n;i++){
    		scanf("%d%d",&x,&y);
    		_add(x,y);
        }
        cin>>m;
        for(int i=1;i<=m;i++){
    		scanf("%d",&x);
    		b[x]=1;
        }
        cin>>K>>X;
    }
    void _pre(int u,int fa){
        dis[u]= b[u] ?0 :-inf;
        for(int i=lst[u];i;i=nxt[i]){
    		int v=to[i];
    		if(v==fa) continue;
    		_pre(v,u);
    		dis[u]=max(dis[u],dis[v]+1);
        }
    }
    void _dfs(int u,int fa,int dep){
        int x1=0,x2=0;
        for(int i=lst[u];i;i=nxt[i]){
    		int v=to[i];
    		if(v==fa) continue;
    		if(dis[v]>dis[x1]){ x2=x1; x1=v; }
    		else if(dis[v]>dis[x2]) x2=v;
        }
        if(x2){
    		int stp=pl-dep,pth;
    		if(tag) pth=max(0,dis[x2]-K-dep+1)/2;
    		else pth=max(0,dis[x2]+1-K-dep+1)/2;
    		maxn=max(maxn,pth);
        }
        if(x1&&dep<pl) _dfs(x1,u,dep+1);
    }
    void _run(){
        dis[0]=-1;
        ans=max(0,dis[X]+1-K)/2;
        pl=max(0,dis[X]-K)/2;
        tag=(dis[X]-K)%2;
        _dfs(X,0,0);
        ans+=maxn;
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
        freopen("x.in","r",stdin);
        freopen("x.out","w",stdout);
    #endif
        _init();
        _pre(X,0);
        _run();
        printf("%d
    ",ans+1);
        return 0;
    }
    
    
  • 相关阅读:
    转载:QTableView中嵌入可视化组件
    pyqt声音输入
    pyqt二进制和图片的转换
    LeetCode(92):反转链表 II
    LeetCode(91):解码方法
    LeetCode(90):子集 II
    LeetCode(89):格雷编码
    LeetCode(88):合并两个有序数组
    LeetCode(87):扰乱字符串
    LeetCode(86):分隔链表
  • 原文地址:https://www.cnblogs.com/BruceW/p/13149510.html
Copyright © 2011-2022 走看看