bzoj1036

树链剖分裸题

 

/**************************************************************

    Problem: 1036

    User: syh0313

    Language: C++

    Result: Accepted

    Time:2500 ms

    Memory:18068 kb

****************************************************************/

 

#include <iostream>

#include <cstdio>

#include <cstdlib>

#include <cmath>

#include <cstring>

#include <string>

#define lch a[n].lc

#define rch a[n].rc

using namespace std;

const int inf=1000000000;

const int maxe=100010;

const int maxd=30010;

int nn,topt,st[maxe],to[maxe],nt[maxe],v[maxd],xx,yy,root=1,cnt,q;

int fa[maxd],rem[maxd],size[maxd],dep[maxd];

int dfn[maxd],line[maxd],dfn_num,top[maxd];

struct tree

{

    int l,r,lc,rc,ma,sum;

}a[20*maxd];

bool f[maxd];

char s[20];

inline void add(int x,int y)

{to[++topt]=y; nt[topt]=st[x]; st[x]=topt;}

inline void dfs1(int x,int d)

{

    dep[x]=d; size[x]=1; f[x]=1;

    int p=st[x]; int ma=0;

    while (p)

    {      

        if (!f[to[p]])

        {

            fa[to[p]]=x;

            dfs1(to[p],d+1);

            size[x]+=size[to[p]];

            if (size[to[p]]>ma) {ma=size[to[p]]; rem[x]=to[p];}

        }

        p=nt[p];

    }

}

inline void dfs2(int x)

{

    f[x]=1; if (rem[fa[x]]==x) top[x]=top[fa[x]];else top[x]=x;

    dfn[x]=++dfn_num; line[dfn_num]=x;

    if (rem[x] && !f[rem[x]]) dfs2(rem[x]);

    int p=st[x];

    while (p)

    {

        if (!f[to[p]]) dfs2(to[p]);

        p=nt[p];

    }

}

inline void updata(int n)

{

    a[n].ma=max(a[lch].ma,a[rch].ma);

    a[n].sum=a[lch].sum+a[rch].sum;

}

inline void build_tree(int &n,int l,int r)

{

    n=++cnt; a[n].l=l; a[n].r=r;

    if (l==r) {a[n].ma=v[line[l]]; a[n].sum=v[line[l]]; return;}

    int mid=(l+r)>>1;

    build_tree(lch,l,mid);

    build_tree(rch,mid+1,r);

    updata(n);

}

inline int qurymax(int n,int L,int R,int l,int r)

{

    if (L==l && R==r) return a[n].ma;

    int mid=(L+R)>>1;

    if (r<=mid) return qurymax(lch,L,mid,l,r);

    else if (l>=mid+1) return qurymax(rch,mid+1,R,l,r);

    else return max(qurymax(lch,L,mid,l,mid),qurymax(rch,mid+1,R,mid+1,r));

}

inline int qmax(int x,int y)

{

    int ans=-inf,l,r;

    while (top[x]!=top[y])

    {

        if (dep[top[x]]<dep[top[y]]) {int cc=x; x=y; y=cc;}

        ans=max(ans,qurymax(root,1,dfn_num,dfn[top[x]],dfn[x]));

        x=fa[top[x]];

    }

    l=min(dfn[x],dfn[y]),r=max(dfn[x],dfn[y]);

    ans=max(ans,qurymax(root,1,dfn_num,l,r));

return ans;

}

inline int qurysum(int n,int L,int R,int l,int r)

{

    if (L==l && R==r) return a[n].sum;

    int mid=(L+R)>>1;

    if (r<=mid) return qurysum(lch,L,mid,l,r);

    else if (l>=mid+1) return qurysum(rch,mid+1,R,l,r);

    else return qurysum(lch,L,mid,l,mid)+qurysum(rch,mid+1,R,mid+1,r);

}

inline int qsum(int x,int y)

{

    int sum=0,l,r;

    while (top[x]!=top[y])

    {

        if (dep[top[x]]<dep[top[y]]) {int cc=x; x=y; y=cc;}

        sum+=qurysum(root,1,dfn_num,dfn[top[x]],dfn[x]);

        x=fa[top[x]];

    }

    l=min(dfn[x],dfn[y]),r=max(dfn[x],dfn[y]);

    sum+=qurysum(root,1,dfn_num,l,r);

return sum;

}

inline void change(int n,int l,int r,int lc)

{

    if (l==r && r==lc) {a[n].ma=yy; a[n].sum=yy; return;}

    if (l==r) return;

    int mid=(l+r)>>1;

    if (lc<=mid) change(lch,l,mid,lc);

    else change(rch,mid+1,r,lc);

    updata(n);

}

int main()

{

    //freopen("1.in","r",stdin);

    //freopen("1.out","w",stdout);

    register int i;

    scanf("%d",&nn);

    for (i=1;i<nn;i++)

    {scanf("%d%d",&xx,&yy); add(xx,yy); add(yy,xx);}

    fa[root]=1; dfs1(root,1);

    memset(f,0,sizeof f); dfs2(root);

    for (i=1;i<=nn;i++) scanf("%d",&v[i]);

    build_tree(root,1,dfn_num);

    scanf("%d",&q);

    while (q--)

    {

        scanf("%s %d %d",s,&xx,&yy);

        if (s[1]=='M') printf("%d\n",qmax(xx,yy));

        else if (s[1]=='S') printf("%d\n",qsum(xx,yy));

        else if (s[1]=='H') change(root,1,dfn_num,dfn[xx]);

    }

return 0;

}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值