spoj1825/ftour2:freetourii——包看得懂/看不懂题解

LuYouQi233 LuYouQi233     2022-10-05     646

关键词:

http://www.spoj.com/problems/FTOUR2/en/

题目大意:给一棵黑白染色的树,求边权和最大且经过黑点不超过K的路径。

————————————————————

前排膜拜hzwer,借(抄)鉴(袭)了神犇的代码与思路,要看简洁的思路的话:http://hzwer.com/5984.html

然而……就算是抄了代码,还是没懂这题怎么做怎么办?

别着急,这道神神神题慢慢来。

——————————————————————

首先判断我们要放什么板子,很显然我们想到的是和树有关的算法,全拎出来一遍发现点分治貌似可行?

那我们点分治就直接求就好了!

然后跟着下面的代码慢慢剖析(与程序有些不符):

1.calcg函数:和普通板子一样,是找重心的。

2.getmaxp函数:处理子树,返回当前子树节点到子树根的路径中最多黑点个数,同时我们主要完成下面数组的更新:

  1.nump[i]:统计i到根节点的路径上的黑点数。

  2.dis[i]:统计i到根节点的路径权值和。

3.getmaxt函数:处理子树的t数组,其中t数组含义如下:

  t[i]:当前子树节点到子树根且经过至多i个黑点的路径的最大权值和。

4.solve函数:处理答案ans,过程如下:

  1.calcg得到重心作为根节点。

  2.getmaxp每个子树的根节点,并且放入我们准备好的s数组里(同时存入子树的根,用make_pair函数更加便捷)。

  3.sort s数组。//原因见4.4

  4.遍历s数组:

    0.初始化t数组//请将该操作放在下面和循环一起进行,不然会卡常数导致TLE

    1.getmaxt子树根。

    2.处理maxn数组,并且更新ans,maxn数组含义如下:

      maxn[i]:以根节点为起点,终点在前面已经搜过的子树中,且该路径至多经过i个黑点,这样的路径的最大权值和。

    我们令当前子树经过的黑点个数为j,前面的子树经过的黑点个数为now,我们显然有:

     maxn[now]=max(maxn[now],maxn[now-1]);

    我们同样显然有:

    if(now+j<=k)ans=max(ans,maxn[now]+t[j]);

    但是显然我们的now不可能全跑一遍(TLE预定),所以我们有两种优化:

      1.now<=s[i-1].first(显然,我们因为sort了所以我们知道now最大不超过s[i-1].first)

      2.j从s[i].first搜到0,期间保证now+j<=k(原因:now越大maxn数组越大所更新的ans越大,所以我们最初就把now放到最大,一来我们更新完了maxn可以不用再更新了,二来此时的maxn[now]+t[j]一定是当前状态最优解。

    咱们继续更新maxn(为了下一步的maxn)

    当当前子树不是最后一棵子树的时候(显然如果是最后一棵的话还更新什么?)显然这么更新即可:maxn[j]=max(maxn[j],t[j]);

    当当前子树是最后一棵子树的时候,我们扫尾将每个子树节点到根节点的距离更新进ans。

  5.删掉重心,递归上述过程。

——————————————————————————————————

好的代码讲解就此结束,最后吐槽一句吧这题卡!常!数!所以把它推向神坛,不然还加那么多奇葩优化干什么……

#include<cmath>
#include<cstdio>
#include<queue>
#include<cctype>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef pair<int,int>pii;
const int N=200001;
inline int read(){
    int X=0,w=0; char ch=0;
    while(!isdigit(ch)) {w|=ch==-;ch=getchar();}
    while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
struct node{
    int w;
    int to;
    int nxt;
}edge[N*2];
vector<pair<int,int> >s;
int cnt,n,m,k,head[N],q[N],size[N],son[N],nump[N],fa[N],maxn[N],t[N],ans,d[N],dis[N];
bool vis[N],is[N];
void add(int u,int v,ll w){
    cnt++;
    edge[cnt].to=v;
    edge[cnt].w=w;
    edge[cnt].nxt=head[u];
    head[u]=cnt;
    return;
}
int calcg(int st){
    int r=0,g,maxn=n;
    q[++r]=st;
    fa[st]=0;
    for(int l=1;l<=r;l++){
    int u=q[l];
    size[u]=1;
    son[u]=0;
    for(int i=head[u];i;i=edge[i].nxt){
        int v=edge[i].to;
        if(vis[v]||v==fa[u])continue;
        fa[v]=u;
        q[++r]=v;
    }
    }
    for(int l=r;l>=1;l--){
    int u=q[l],v=fa[u];
    if(r-size[u]>son[u])son[u]=r-size[u];
    if(son[u]<maxn)g=u,maxn=son[u];
    if(!v)break;
    size[v]+=size[u];
    if(size[u]>son[v])son[v]=size[u];
    }
    return g;
}
inline int getmaxp(int st,ll L){
    int r=0,maxp=0;
    q[++r]=st;
    nump[st]=is[st];
    dis[st]=L;
    fa[st]=0;
    maxp=max(maxp,nump[st]);
    for(int l=1;l<=r;l++){
    int u=q[l];
    for(int i=head[u];i;i=edge[i].nxt){
        int v=edge[i].to;
        int w=edge[i].w;
        if(vis[v]||v==fa[u])continue;
        fa[v]=u;
        dis[v]=dis[u]+w;
        nump[v]=nump[u]+is[v];
        maxp=max(maxp,nump[v]);
        q[++r]=v;
    }
    }
    return maxp;
}
inline void getmaxt(int st){
    int r=0;
    q[++r]=st;
    t[nump[st]]=max(t[nump[st]],dis[st]);
    for(int l=1;l<=r;l++){
    int u=q[l];
    for(int i=head[u];i;i=edge[i].nxt){
        int v=edge[i].to;
        int w=edge[i].w;
        if(vis[v]||v==fa[u])continue;
        t[nump[v]]=max(t[nump[v]],dis[v]);
        q[++r]=v;
    }
    }
    return;
}
void solve(int u){
    int g=calcg(u);
    vis[g]=1;s.clear();
    for(int i=head[g];i;i=edge[i].nxt){
    int v=edge[i].to;
    int w=edge[i].w;
    if(!vis[v])s.push_back(pii(getmaxp(v,w),v));
    }
    sort(s.begin(),s.end());
    if(is[g])k--;
    for(int i=0;i<s.size();i++){
    getmaxt(s[i].second);
    int now=0;
    if(i){
        for(int j=s[i].first;j>=0;j--){
        while(now+j<k&&now<s[i-1].first){
            now++;
            maxn[now]=max(maxn[now],maxn[now-1]);
        }
        if(now+j<=k)ans=max(ans,maxn[now]+t[j]);
        }
    }
    if(i!=s.size()-1){
        for(int j=0;j<=s[i].first;j++){
        maxn[j]=max(maxn[j],t[j]);
        t[j]=0;
        }
    }else{
        for(int j=0;j<=s[i].first;j++){
        if(j<=k)ans=max(ans,max(t[j],maxn[j]));
        maxn[j]=t[j]=0;
        }
    }
    }
    if(is[g])k++;
    for(int i=head[g];i;i=edge[i].nxt){
    int v=edge[i].to;
    if(!vis[v])solve(v);
    }
    return;
}
int main(){
    n=read();
    k=read();
    m=read();
    for(int i=1;i<=m;i++)is[read()]=1;
    for(int i=1;i<n;i++){
    int u=read();
    int v=read();
    int w=read();
    add(u,v,w);
    add(v,u,w);
    }
    solve(1);
    printf("%d
",ans);
    return 0;
}

 

[spoj1825]ftour2(代码片段)

我们知道,树上两个点的LCA要么是当前根节点,要么不是。。所以两个点间的最短路径要么经过当前根节点,要么在一棵当前根节点的子树中。。考虑点分治,于是在原来同一子树中的两个点必然在一次分治中变为路径经过当前... 查看详情

为啥我的 SPOJ GCD2 代码在 SPOJ 上出错?

】为啥我的SPOJGCD2代码在SPOJ上出错?【英文标题】:WhydoesmycodeforSPOJGCD2erroronSPOJ?为什么我的SPOJGCD2代码在SPOJ上出错?【发布时间】:2015-08-3118:05:22【问题描述】:以下是SPOJGCD2的代码。它在我的机器和Ideone上运行良好,但在SPOJ上... 查看详情

[spoj7258]lexicographicalsubstringsearch

[SPOJ7258]LexicographicalSubstringSearch试题描述LittleDaniellovestoplaywithstrings!Healwaysfindsdifferentwaystohavefunwithstrings!Knowingthat,hisfriendKinandecidedtotesthisskillssohegavehimastring S& 查看详情

[spoj1812]longestcommonsubstringii

[SPOJ1812]LongestCommonSubstringII试题描述Astringisfinitesequenceofcharactersoveranon-emptyfinitesetΣ.Inthisproblem,Σisthesetoflowercaseletters.Substring,alsocalledfactor,isaconsecutivesequenceofcharacter 查看详情

[spoj8222]substrings

[SPOJ8222]Substrings试题描述YouaregivenastringSwhichconsistsof250000lowercaselatinlettersatmost.WedefineF(x)asthemaximalnumberoftimesthatsomestringwithlengthxappearsinS.Forexampleforstring‘ababa‘F(3)willb 查看详情

SPOJ-下一个回文

】SPOJ-下一个回文【英文标题】:SPOJ-Thenextpalindrome【发布时间】:2018-08-2507:42:26【问题描述】:问题-https://www.spoj.com/problems/PALIN/-输入测试用例个数-输入测试用例-输出与输入的测试用例最接近的回文数,不包括用例本身我的尝... 查看详情

SPOJ 问题 - 这里出了啥问题?

】SPOJ问题-这里出了啥问题?【英文标题】:SPOJquestion-WHatisgoingwronghere?SPOJ问题-这里出了什么问题?【发布时间】:2011-06-2416:54:53【问题描述】:我正在回答这个spoj问题:http://www.spoj.pl/problems/JAVAC/我用C++对提交进行了编码。我... 查看详情

[spoj839]optimalmarks

[SPOJ839]OptimalMarks试题描述Youaregivenanundirectedgraph(G(V,E)).Eachvertexhasamarkwhichisanintegerfromtherange([0..2^{31}-1]).Differentvertexesmayhavethesamemark.Foranedge((u,v)),wedefine(Cost(u, 查看详情

spoj8222

地址:题目:NSUBSTR-Substringsnotags  YouaregivenastringSwhichconsistsof250000lowercaselatinlettersatmost.WedefineF(x)asthemaximalnumberoftimesthatsomestringwithlengthxappearsinS.Forexampleforstri 查看详情

[spoj10707]countonatreeii

[SPOJ10707]CountonatreeII试题描述Youaregivenatreewith N nodes.Thetreenodesarenumberedfrom 1 to N.Eachnodehasanintegerweight.Wewillaskyoutoperformthefollowingoperation:uv :ask 查看详情

运行时错误 (SIGABRT) - SPOJ

】运行时错误(SIGABRT)-SPOJ【英文标题】:runtimeerror(SIGABRT)-SPOJ【发布时间】:2016-03-3114:15:21【问题描述】:我的代码在代码块中运行良好,但是当我提交时显示runtimesigabrt错误,这个错误是什么意思?当我将指针数组的大小初始化... 查看详情

spoj-high

Insomecountriesbuildinghighwaystakesalotoftime...Maybethat‘sbecausetherearemanypossiblitiestoconstructanetworkofhighwaysandengineerscan‘tmakeuptheirmindswhichonetochoose.Supposewehavealistofcitiesthat 查看详情

spoj-blmirinaarcherytraining

Miranaisanarcherwithsuperpower.Everyarrowsheshootswillgetstrongerthefurtherittravels.Miranaiscurrentlyonthewaytowarzone.Sincetheroadisstillalongway,Miranaremembersaboutwhenshe‘sstillintraining.Ineacho 查看详情

spoj-bitdiffbitdifference

GivenanintegerarrayofNintegers,findthesumofbitdifferencesinallthepairsthatcanbeformedfromarrayelements.Bitdifferenceofapair(x,y)isthecountofdifferentbitsatthesamepositionsinbinaryrepresentationsofxand 查看详情

spoj-bgshoot

TheproblemisaboutMr.BGwhoisagreathunter.Todayhehasgonetoadenseforestforhuntingandkillinganimals.Sadly,hehasonlyonebulletinhisgun.Hewantstokillasmanyanimalsaspossiblewithonlyonebullet.Hehasalreadyknown 查看详情

spoj3273

传送门: 这是一道treap的模板题,不要问我为什么一直在写模板题 依旧只放代码1//SPOJ32732//byCydiater3//2016.8.314#include<iostream>5#include<cstring>6#include<ctime>7#include<cmath>8#include<cstdlib& 查看详情

spoj-trnglmaketriangle

 MakeTriangleChayanikalovesMathematics.Sheislearninganewchaptergeometry.Whilereadingthechapteraquestioncameinhermind.Givenaconvexpolygonofnsides.Inhowmanywaysshecanbreakitintotriangles,bycuttingi 查看详情

spoj 上的防污系统

】spoj上的防污系统【英文标题】:Antiblotsystemonspoj【发布时间】:2019-01-1908:44:45【问题描述】:我遇到了一个问题AntiBlot我在所有测试用例上执行了我的程序,我得到了正确的答案。但我仍然在spoj上得到“错误答案”我尝试过的... 查看详情