2018青岛网络赛B

给一颗树,其中树中有一些红色的点,每个点到距离它最近的祖先红点的距离称为它的距离。

每次给一个点子集,可以选择把树中任意一个点变为红色,问怎样让子集里的点的距离最大值最小。

当只有两个点时,肯定是先找到他们的 lca 然后先判断将 lca 染红是否可以让最大的距离变小,如果有一个点的祖先红点在 lca 的子树里那么不管染哪里的点最大的距离最小必定是两个点中的次小值,当有多个点时只需要将点以距离从大到小排序然后依次按这个规则判断即可。

只不过多个点时如果将 lca 染红最大的距离反而比不染变大了,那么染上一个 lca 时的答案时最小的最大距离。

因为给的子集中点总个数不超过1e6,所以复杂度可以接受。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int M = 1e5+7;
int _,n,m,q;
int red[M];
int cnt,head[M],tot,in[M],out[M];
int f[M][22],deep[M],far[M];
ll dis[M];
struct edge
{
    int v,next;ll w;
}e[M<<1];
void init(){
    tot=cnt=0;memset(head,-1,sizeof(head));memset(red,0,sizeof(red));
    memset(dis,0,sizeof(dis));
}
void add(int u,int v,ll w){
    e[++cnt].v=v;e[cnt].w=w;e[cnt].next=head[u];
    head[u]=cnt;
}
void dfs(int u,int fa,int d,ll len,int fared){//dfs(1,-1,0)
    in[u]=++tot;
    deep[u]=d;
    dis[u]=len-dis[fared];
    if(red[u])
        far[u]=u;
    else
        far[u]=fared;
    for(int i=head[u];~i;i=e[i].next){
        int v=e[i].v;ll w=e[i].w;
        if(v==fa) continue;
        if(red[u]) dfs(v,u,d+1,dis[u]+w,u);
        else dfs(v,u,d+1,len+w,fared);
        f[v][0]=u;
    }
    out[u]=tot;
    return ;
}
void work(){//RMQ
    for(int i=1;i<20;i++)
        for(int j=1;j<=n;j++) f[j][i]=f[f[j][i-1]][i-1];
}
int lca(int x,int y){//lca
    if(deep[x]<deep[y]) swap(x,y);
    int dt=deep[x]-deep[y];
    for(int i=0;i<20;i++) if(dt&(1<<i)) x=f[x][i];
    if(x==y) return x;
    for(int i=19;i>=0;i--) if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
    return f[x][0];
}
bool cmp(int &x,int &y){
    return dis[x]>dis[y];
}
int que[M];
int main(){
    //freopen("1.in","r",stdin);
    //freopen("1.out","w",stdout);*/
    scanf("%d",&_);
    while(_--){
        init();
        scanf("%d%d%d",&n,&m,&q);
        for(int i=1;i<=m;i++){
            int x;
            scanf("%d",&x);
            red[x]=1;
        }
        for(int i=1;i<n;i++){
            int from,to;ll val;
            scanf("%d%d%lld",&from,&to,&val);
            add(from,to,val);add(to,from,val);
        }
        dfs(1,0,0,0,1);
        work();
        while(q--){
            int k;
            scanf("%d",&k);
            for(int i=1;i<=k;i++){
                scanf("%d",&que[i]);
                if(red[que[i]]) dis[que[i]]=0;
            }
            sort(que+1,que+k+1,cmp);
            ll ans=0;
            int prepos=que[1];
            for(int i=2;i<=k;i++){
                int lc=lca(prepos,que[i]);
                if((in[far[prepos]]>=in[lc]&&in[far[prepos]]<=out[lc])||((in[far[que[i]]]>=in[lc]&&in[far[que[i]]]<=out[lc]))){
                    ans=max(ans,dis[que[i]]);
                    break;
                }
                if(max(ans,dis[que[i]])>=max(dis[que[i]]-dis[lc],ans+dis[prepos]-dis[lc])){
                    ans=max(dis[que[i]]-dis[lc],ans+dis[prepos]-dis[lc]);
                    prepos=lc;
                }
                else{
                    ans=max(ans,dis[que[i]]);
                    break;
                }
            }
            printf("%lld\n",ans);
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/LMissher/p/9662137.html

时间: 2024-08-02 23:43:47

2018青岛网络赛B的相关文章

ACM-ICPC 2018青岛网络赛-H题

把这题的每个点分成两种情况看,如果是从这个点开始,0算作2,1算作1,如果是中间点或者是结束点,如果和前面的相同看作2,不相同看作1 #include <iostream> #include <string> #include <string.h> using namespace std; int main() { ios::sync_with_stdio(false); int t; cin >> t; while (t--) { int a, b; st

ACM-ICPC 2018青岛网络赛-A题 Saving Tang Monk II

做法:优先队列 题目1 : Saving Tang Monk II 时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描述 <Journey to the West>(also <Monkey>) is one of the Four Great Classical Novels of Chinese literature. It was written by Wu Cheng'en during the Ming Dynasty. In this novel,

HDU 5880 Family View (2016 青岛网络赛 C题,AC自动机)

题目链接  2016 青岛网络赛  Problem C 题意  给出一些敏感词,和一篇文章.现在要屏蔽这篇文章中所有出现过的敏感词,屏蔽掉的用$'*'$表示. 建立$AC$自动机,查询的时候沿着$fail$指针往下走,当匹配成功的时候更新$f[i]$ $f[i]$表示要屏蔽以第$i$个字母结尾的长度为$f[i]$的字符串. 原文地址:https://www.cnblogs.com/cxhscst2/p/8452147.html

2018 CCPC网络赛

2018 CCPC网络赛 Buy and Resell 题目描述:有一种物品,在\(n\)个地点的价格为\(a_i\),现在一次经过这\(n\)个地点,在每个地点可以买一个这样的物品,也可以卖出一个物品,问最终赚的钱的最大值. solution 用两个堆来维护,一个堆维护已经找到卖家的,一个堆维护还没找到卖家的. 对于第\(i\)个地点,在已经找到卖家的堆里找出卖的钱的最小值,如果最小值小于\(a_i\),则将卖家换成\(i\),然后将原来的卖家放到没找到卖家的那里:如果最小值对于\(a_i\)

2018徐州网络赛H. Ryuji doesn&#39;t want to study

题目链接: https://nanti.jisuanke.com/t/31458 题解: 建立两个树状数组,第一个是,a[1]*n+a[2]*(n-1)....+a[n]*1;第二个是正常的a[1],a[2],a[3]...a[n] #include "bits/stdc++.h" using namespace std; #define ll long long const int MAXN=1e5+10; ll sum[MAXN],ans[MAXN]; ll num[MAXN];

ACM-ICPC 2018徐州网络赛-H题 Ryuji doesn&#39;t want to study

C*M....死于update的一个long long写成int了 心累 不想写过程了 ******** 树状数组,一个平的一个斜着的,怎么斜都行 题库链接:https://nanti.jisuanke.com/t/31460 #include <iostream> #include <cstring> #define ll long long #define lowbit(x) (x & -x) using namespace std; const int maxn =

2018 CCPC网络赛 Dream&amp;&amp;Find Integer

首先这场比赛打得很难受,因为是第一次打网络赛而且也是比较菜的那种,所以对这场网络赛还是挺期待和紧张的,但是在做题的过程中,主要的压力不是来自于题目,更多的来自于莫干山...从12.40-2.00所有的题目都不判了,中间也就写了1003和1004但是都不知道结果就很难受, 然后一直不判就已经没什么看其他题的兴趣了,然后上床休息了一会,直到说杭电的评测机好了,之后才上去继续做题.然后..一直在写1001和1009..后面也没有写出来..直到比赛结束 首先说下1004 签到题竟然写了这么久,而且用了c

计蒜客 2018南京网络赛 I Skr ( 回文树 )

题目链接 题意 : 给出一个由数字组成的字符串.然后要你找出其所有本质不同的回文子串.然后将这些回文子串转化为整数后相加.问你最后的结果是多少.答案模 1e9+7 分析 : 应该可以算是回文树挺裸的题目吧 可惜网络赛的时候不会啊.看着马拉车想半天.卒... 对于每一个节点.记录其转化为整数之后的值 然后在回文串插入字符的时候 不断维护这个信息就行了 其实很好理解.看一下代码就懂了 ( 如果你学过回文树的话... ) 就是多加了变量 val .维护语句 #include<bits/stdc++.h

2018 ICPC青岛网络赛 B. Red Black Tree(倍增lca好题)

BaoBao has just found a rooted tree with n vertices and (n-1) weighted edges in his backyard. Among the vertices, of them are red, while the others are black. The root of the tree is vertex 1 and it's a red vertex.Let's define the cost of a red verte