P2590 [ZJOI2008]树的统计

操作:

I. CHANGE u t : 把结点u的权值改为t

II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值

III. QSUM u v: 询问从点u到点v的路径上的节点的权值和

标签:树剖+线段树 模板题。

转化一下题意:

操作1:单点修改。

操作2:利用树剖求LCA的过程求经过的点的权值的最大值。

操作3:利用树剖求LCA的过程累加经过的点的权值之和。

Code:

#include<cstdio>
#include<iostream>
#include<string>
#define ri register int
using namespace std;

const int MAXN=60020;
int n,m,q,u[MAXN],v[MAXN],w[MAXN],fst[MAXN],nxt[MAXN],num,t;
int fa[MAXN],deep[MAXN],siz[MAXN],son[MAXN],cmax[MAXN],top[MAXN],dfn[MAXN],rk[MAXN],cur,a[MAXN];
int l[MAXN<<2],r[MAXN<<2],maxn[MAXN<<2],sum[MAXN<<2];
string ss;

void dfs1(int x,int father,int dep)
{
    fa[x]=father,deep[x]=dep,siz[x]=1;
    for(ri k=fst[x];k>0;k=nxt[k])
        if(v[k]!=father)
        {
            dfs1(v[k],x,dep+1);
            if(siz[v[k]]>cmax[x])	cmax[x]=siz[v[k]],son[x]=v[k];
            siz[x]+=siz[v[k]];
        }
}

void dfs2(int x,int anc)
{
    top[x]=anc,dfn[x]=++cur,rk[cur]=x,a[cur]=w[x];
    if(son[x]!=0)	dfs2(son[x],anc);
    for(ri k=fst[x];k>0;k=nxt[k])
        if(v[k]!=fa[x]&&v[k]!=son[x])	dfs2(v[k],v[k]);
}

void pushup(int p)
{
    sum[p]=sum[p <<1]+sum[p <<1|1];
    maxn[p]=max(maxn[p <<1],maxn[p <<1|1]);	
}

void build(int p,int lft,int rit)
{
    l[p]=lft,r[p]=rit;
    if(lft==rit)	{ sum[p]=a[lft]; maxn[p]=a[lft]; return; }
    int mid=(lft+rit)>>1;
    build(p <<1,lft,mid);
    build(p <<1|1,mid+1,rit);
    pushup(p);
}

void update(int p,int pla,int k)
{
    if(l[p]==pla&&r[p]==pla)
    {
        sum[p]=k,maxn[p]=k;
        return; 
    }
    if(pla<=r[p <<1])    update(p <<1,pla,k);
    if(l[p <<1|1]<=pla)    update(p <<1|1,pla,k);
    pushup(p);
}

int qmax(int p,int lft,int rit)
{
    if(lft<=l[p]&&r[p]<=rit)	return maxn[p];
    int ans=-1e9;
    if(lft<=r[p <<1])    ans=qmax(p <<1,lft,rit);
    if(l[p <<1|1]<=rit)	   ans=max(ans,qmax(p <<1|1,lft,rit));
    return ans;	
}

int LCAmax(int x,int y)
{
    int ans=-1e9;
    while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]])	swap(x,y);
        ans=max(ans,qmax(1,dfn[top[x]],dfn[x]));
        x=fa[top[x]];
    }
    if(deep[x]<deep[y])	swap(x,y);
    ans=max(ans,qmax(1,dfn[y],dfn[x]));
    return ans;	
}

int qsum(int p,int lft,int rit)
{
    if(lft<=l[p]&&r[p]<=rit)	return sum[p];
    int ans=0;
    if(lft<=r[p <<1])    ans=qsum(p <<1,lft,rit);
    if(l[p <<1|1]<=rit)	   ans+=qsum(p <<1|1,lft,rit);
    return ans;
}

int LCAsum(int x,int y)
{
    int ans=0;
    while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]])	swap(x,y);
        ans+=qsum(1,dfn[top[x]],dfn[x]);
        x=fa[top[x]];
    }
    if(deep[x]<deep[y])	swap(x,y);
    ans+=qsum(1,dfn[y],dfn[x]);
    return ans;
}

int main()
{
    scanf("%d",&n);
    m=(n-1)<<1;
    for(ri i=1;i<=m;i+=2)
    {
        scanf("%d%d",&u[i],&v[i]);
        nxt[i]=fst[u[i]],fst[u[i]]=i;
        u[i+1]=v[i],v[i+1]=u[i];
        nxt[i+1]=fst[u[i+1]],fst[u[i+1]]=i+1;
    }
    for(ri i=1;i<=n;i++)	scanf("%d",&w[i]);
    dfs1(1,1,0);
    dfs2(1,1);
    build(1,1,n);
    scanf("%d",&q);
    for(int i=1;i<=q;i++)
    {
        cin>>ss>>num>>t;
        if(ss=="CHANGE")    update(1,dfn[num],t);
        if(ss=="QMAX")    cout<<LCAmax(num,t)<<'\n';
        if(ss=="QSUM")    cout<<LCAsum(num,t)<<'\n';
    }
    return 0;
}

 

C语言-光伏MPPT算法:电导增量法扰动观察法+自动全局搜索Plecs最大功率跟踪算法仿真内容概要:本文档主要介绍了一种基于C语言实现的光伏最大功率点跟踪(MPPT)算法,结合电导增量法与扰动观察法,并引入自动全局搜索策略,利用Plecs仿真工具对算法进行建模与仿真验证。文档重点阐述了两种经典MPPT算法的原理、优缺点及其在不同光照和温度条件下的动态响应特性,同时提出一种改进的复合控制策略以提升系统在复杂环境下的跟踪精度与稳定性。通过仿真结果对比分析,验证了所提方法在快速性和准确性方面的优势,适用于光伏发电系统的高效能量转换控制。; 适合人群:具备一定C语言编程基础和电力电子知识背景,从事光伏系统开发、嵌入式控制或新能源技术研发的工程师及高校研究人员;工作年限1-3年的初级至中级研发人员尤为适合。; 使用场景及目标:①掌握电导增量法与扰动观察法在实际光伏系统中的实现机制与切换逻辑;②学习如何在Plecs中搭建MPPT控制系统仿真模型;③实现自动全局搜索以避免传统算法陷入局部峰值问题,提升复杂工况下的最大功率追踪效率;④为光伏逆变器或太阳能充电控制器的算法开发提供技术参考与实现范例。; 阅读建议:建议读者结合文中提供的C语言算法逻辑与Plecs仿真模型同步学习,重点关注算法判断条件、步长调节策略及仿真参数设置。在理解基本原理的基础上,可通过修改光照强度、温度变化曲线等外部扰动因素,进一步测试算法鲁棒性,并尝试将其移植到实际嵌入式平台进行实验验证。
题目描述 有一个 $n$ 个点的棋盘,每个点上有一个数字 $a_i$,你需要从 $(1,1)$ 走到 $(n,n)$,每次只能往右或往下走,每个格子只能经过一次,路径上的数字和为 $S$。定义一个点 $(x,y)$ 的权值为 $a_x+a_y$,求所有满足条件的路径中,所有点的权值和的最小值。 输入格式 第一行一个整数 $n$。 接下来 $n$ 行,每行 $n$ 个整数,表示棋盘上每个点的数字。 输出格式 输出一个整数,表示所有满足条件的路径中,所有点的权值和的最小值。 数据范围 $1\leq n\leq 300$ 输入样例 3 1 2 3 4 5 6 7 8 9 输出样例 25 算法1 (形dp) $O(n^3)$ 我们可以先将所有点的权值求出来,然后将其看作是一个有权值的图,问题就转化为了在这个图中求从 $(1,1)$ 到 $(n,n)$ 的所有路径中,所有点的权值和的最小值。 我们可以使用形dp来解决这个问题,具体来说,我们可以将这个图看作是一棵,每个点的父节点是它的前驱或者后继,然后我们从根节点开始,依次向下遍历,对于每个节点,我们可以考虑它的两个儿子,如果它的两个儿子都被遍历过了,那么我们就可以计算出从它的左儿子到它的右儿子的路径中,所有点的权值和的最小值,然后再将这个值加上当前节点的权值,就可以得到从根节点到当前节点的路径中,所有点的权值和的最小值。 时间复杂度 形dp的时间复杂度是 $O(n^3)$。 C++ 代码 算法2 (动态规划) $O(n^3)$ 我们可以使用动态规划来解决这个问题,具体来说,我们可以定义 $f(i,j,s)$ 表示从 $(1,1)$ 到 $(i,j)$ 的所有路径中,所有点的权值和为 $s$ 的最小值,那么我们就可以得到如下的状态转移方程: $$ f(i,j,s)=\min\{f(i-1,j,s-a_{i,j}),f(i,j-1,s-a_{i,j})\} $$ 其中 $a_{i,j}$ 表示点 $(i,j)$ 的权值。 时间复杂度 动态规划的时间复杂度是 $O(n^3)$。 C++ 代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值