Hrbust 2065 萌萌哒十五酱的苹果~【树链剖分+线段树】

萌萌哒十五酱的苹果~
Time Limit: 3000 MSMemory Limit: 6000 K
Total Submit: 42(7 users)Total Accepted: 5(5 users)Rating: Special Judge: No
Description
    十五家的院子很大诶~
    所以可以种树啊~
    所以就种了棵苹果树啊(我在废话昂,,,,,,

    树上面有n个节点,编号是1~n,每个节点上面有wi个苹果啦><

    苹果当然要数一下啦~(诶!!这是为什么。。。
    十五自己数起来太累了嘛~所以十五希望你可以帮忙数苹果
    总共大概有这些情况(喂喂!!什么叫大概啊!
    1.CHANGE u t:树上面标号为u的节点的苹果数改为t
    2.QMAX u v:询问点u到v的路径上苹果树最大的苹果数是多少
    3.QSUM u v:询问点u到v上总共有多少个苹果~
Input

    多组数据QAQ

    每组数据第一行为一个整数n(1<=n<=30000),表示苹果树上节点的个数。

    接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。

    接下来n行,每行一个整数,第i行的整数wi表示节点i的苹果个数。

    接下来1行,为一个整数 q(0<=q<=200000),表示操作的总数。

    接下来q行,每行一个操作,以“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。 

    中途操作中每个节点的权值w保证在-30000到 30000之间。

Output

    多组数据QAQ

    对于十五的每一个“QMAX”或者“QSUM”,都要输出一个整数表示结果哦~

    ><

Sample Input

4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4


Sample Output
4
1
2
2
10
6
5
6
5
16
Hint

十五酱最萌了昂~

Source
HCPC2014校赛训练赛 6

思路:


暴力剖分然后线段树维护一下。

板子题,码农一下。练习一下算法手敲熟练度。


值得注意一个点是,这个题卡了内存,不能开太大方,随之可能改了内存变小之后,吃了屎一样可能会忘记线段树*4的问题。

Wa了好半天= =


Ac代码:


#include<stdio.h>
#include<string.h>
#include<iostream>
#include<vector>
using namespace std;
int n;
vector<int>mp[30500];
int val[30500];
#define lson l,m,rt*2
#define rson m+1,r,rt*2+1
int sum[30500*4];
int maxn[30500*4];
void pushup(int rt)
{
    maxn[rt]=max(maxn[rt*2],maxn[rt*2+1]);
    sum[rt]=sum[rt*2]+sum[rt*2+1];
}
void update(int p,int c,int l,int r,int rt)
{
    if(l==r)
    {
        sum[rt]=c;
        maxn[rt]=c;
        return ;
    }
    pushup(rt);
    int m=(l+r)/2;
    if(p<=m)update(p,c,lson);
    if(p>m)update(p,c,rson);
    pushup(rt);
}
void build(int l,int r,int rt)
{
    if(l==r)
    {
        sum[rt]=0;
        maxn[rt]=0;
        return ;
    }
    int m=(l+r)/2;
    build(lson);
    build(rson);
    pushup(rt);
}
int query_sum(int L,int R,int l,int r,int rt)
{
    if(l>=L&&r<=R)
    {
        return sum[rt];
    }
    pushup(rt);
    int ans=0;
    int m=(l+r)/2;
    if(L<=m)ans+=query_sum(L,R,lson);
    if(R>m)ans+=query_sum(L,R,rson);
    pushup(rt);
    return ans;
}
int query_maxn(int L,int R,int l,int r,int rt)
{
    if(l>=L&&r<=R)
    {
        return maxn[rt];
    }
    pushup(rt);
    int ans=-0x3f3f3f3f;
    int m=(l+r)/2;
    if(L<=m)ans=max(ans,query_maxn(L,R,lson));
    if(R>m)ans=max(ans,query_maxn(L,R,rson));
    pushup(rt);
    return ans;
}
int cnt;
int size[30500];
int fa[30500];
int son[30500];
int depth[30500];
int Top[30500];
int dfn[30500];
void Dfs(int u,int from,int d)
{
    depth[u]=d;size[u]=1;fa[u]=from;son[u]=-1;
    for(int i=0;i<mp[u].size();i++)
    {
        int v=mp[u][i];
        if(v==from)continue;
        Dfs(v,u,d+1);
        size[u]+=size[v];
        if(son[u]==-1||size[v]>size[son[u]])
        {
            son[u]=v;
        }
    }
}
void Dfs2(int u,int from,int top)
{
    dfn[u]=++cnt;Top[u]=top;
    if(son[u]!=-1)Dfs2(son[u],u,top);
    for(int i=0;i<mp[u].size();i++)
    {
        int v=mp[u][i];
        if(v==from||v==son[u])continue;
        Dfs2(v,u,v);
    }
}
void Slove_sum(int x,int y)
{
    int ans=0;
    int fx=Top[x],fy=Top[y];
    while(fx!=fy)
    {
        if(depth[fx]<depth[fy])
        {
            swap(fx,fy);
            swap(x,y);
        }
        ans+=query_sum(dfn[fx],dfn[x],1,n,1);
        x=fa[fx],fx=Top[x];
    }
    if(depth[x]<depth[y])swap(x,y);
    ans+=query_sum(dfn[y],dfn[x],1,n,1);
    printf("%d\n",ans);
}
void Slove_maxn(int x,int y)
{
    int ans=-0x3f3f3f3f;
    int fx=Top[x],fy=Top[y];
    while(fx!=fy)
    {
        if(depth[fx]<depth[fy])
        {
            swap(fx,fy);
            swap(x,y);
        }
        ans=max(ans,query_maxn(dfn[fx],dfn[x],1,n,1));
        x=fa[fx],fx=Top[x];
    }
    if(depth[x]<depth[y])swap(x,y);
    ans=max(ans,query_maxn(dfn[y],dfn[x],1,n,1));
    printf("%d\n",ans);
}
int main()
{
    while(~scanf("%d",&n))
    {
        memset(maxn,0,sizeof(maxn));
        memset(sum,0,sizeof(sum));
        for(int i=1;i<=n;i++)mp[i].clear();
        for(int i=1;i<=n-1;i++)
        {
            int x,y;scanf("%d%d",&x,&y);
            mp[x].push_back(y);
            mp[y].push_back(x);
        }
        cnt=0;
        Dfs(1,-1,1);
        Dfs2(1,-1,1);
        build(1,n,1);
        for(int i=1;i<=n;i++)scanf("%d",&val[i]),update(dfn[i],val[i],1,n,1);
        int q;scanf("%d",&q);
        while(q--)
        {
            char s[150];
            scanf("%s",s);
            if(s[1]=='S')
            {
                int x,y;scanf("%d%d",&x,&y);
                Slove_sum(x,y);
            }
            if(s[1]=='M')
            {
                int x,y;scanf("%d%d",&x,&y);
                Slove_maxn(x,y);
            }
            if(s[0]=='C')
            {
                int x,y;scanf("%d%d",&x,&y);
                update(dfn[x],y,1,n,1);
            }
        }
    }
}








  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值