4/10

//晚上更新了

树上子链

求树上最长链(或者说树的直径、树上距离最远的两点距离,树中所有最短路径距离的最大值)的模板题

参考资料1(by ROCKYONE)

参考资料2(by forever_dreams)

1.树形DP(可以有效处理负边权)
2.两次dfs或bfs(无法处理负边权)

树的直径 = (在某个节点的子树中以它为端点的) 最长链 + 次长链
(连接起来可以得到一条更长的链,当然有时没有次长链,仅是一条最长链)

mx表示以i为根的子树中,i到叶子结点距离(不包括p[i])的最大值,即上面说的最长链

mx2表示以i为根的子树中,i到叶子结点距离(不包括p[i])的次大值,即上面说的次长链

ans=max(ans,max(mx+p[i],mx+mx2+p[i]))//p是点权
由于mx2>=0,所以可以直接写为ans=max(ans,mx+mx2+p[x])

#include<cstdio>
using namespace std;
#define max(a,b) (a>b ? a:b)
#define ll long long
const int N=100005;
const ll inf=-0x3f3f3f3f3f3f3f3f;
struct edge{
    int v,h;
}e[N<<1];
int n,p[N],head[N],tot;
ll ans=inf;//注意点权有负数
inline void add(int u,int v){
    e[++tot]=(edge){
        v,head[u]
    },head[u]=tot;
}
ll dfs(int x,int fa){
    ll tmp,mx=0,mx2=0;//最长链与次长链初始化为0,如果链为负数我们不如不要
    for (int i=head[x],v;i;i=e[i].h)
    if ((v=e[i].v)^fa){
        tmp=dfs(v,x);
        if (tmp>mx) mx2=mx,mx=tmp;
        else if (tmp>mx2) mx2=tmp;
    }
    ans=max(ans,mx+mx2+p[x]);
    return mx+p[x];//最长链可以继续上传更新答案,但最长链和次长链连接起来不能上传
}
int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&p[i]);
    for (int i=1,x,y;i<n;i++)
     scanf("%d %d",&x,&y),add(x,y),add(y,x);
    dfs(1,-1);
    printf("%lld",ans);
}

A

J —计算A+B

//注意下这些情况++0,0++,02+++0,02+02+02

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cmath>
#include <math.h>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <stack>
#define lowbit(i)((i)&(-i))
using namespace std;
typedef long long ll;
const int MAX=1e5+20;
const int INF=0x3f3f3f3f;
const int MOD=1000000007;
const int SQR=632;//633块,632个
void add(vector<int>&a,vector<int>&b)
{
    vector<int>c;
    int t=0;
    for(int i=0;i<a.size()||i<b.size();i++)
    {
        if(i<a.size())t+=a[i];
        if(i<b.size())t+=b[i];
        c.push_back(t%10);
        t/=10;
    }
    if(t)c.push_back(t);
    while(c.back()==0&&c.size()>1)
        c.pop_back();
    for(int i=c.size()-1;i>=0;i--)
        cout<<c[i];
}
int main()
{
    string s;
    int n;
    scanf("%d",&n);
    for(int i=0;i<n;i++)
    {
        cin>>s;
        string a="",b="";
        int t=0,num=0;
        for(int j=0;j<s.size();j++)
        {
            if(s[j]=='+')
                num++;
        }
        if(num!=1)
        {
            printf("skipped\n");
            continue;
        }
        while(s[t]!='+')
        {
            a+=s[t];
            t++;
        }
        t++;
        while(t<s.size())
        {
            b+=s[t];
            t++;
        }
        vector<int>vta,vtb;
        for(int j=a.size()-1;j>=0;j--)
            vta.push_back(a[j]-'0');
        for(int j=b.size()-1;j>=0;j--)
            vtb.push_back(b[j]-'0');
        if(a==""||b=="")
            printf("skipped\n");
        else
        {
            add(vta,vtb);
            cout<<endl;
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值