BZOJ1036: [ZJOI2008]树的统计Count

Description

  一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w。我们将以下面的形式来要求你对这棵树完成一些操作: I. CHANGE u t : 把结点u的权值改为t II. QMAX u v: 询问从点u到点v的路径上的节点的最大权值 III. QSUM u v: 询问从点u到点v的路径上的节点的权值和 注意:从点u到点v的路径上的节点包括u和v本身

Input

  输入的第一行为一个整数n,表示节点的个数。接下来n – 1行,每行2个整数a和b,表示节点a和节点b之间有一条边相连。接下来n行,每行一个整数,第i行的整数wi表示节点i的权值。接下来1行,为一个整数q,表示操作的总数。接下来q行,每行一个操作,“CHANGE u t”或者“QMAX u v”或者“QSUM u v”的形式给出。 
对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。

Output

  对于每个“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
 
树链剖分 
点权 单点修改 线段树维护区间最大值,和
#include <bits/stdc++.h>
#define ull unsigned long long
using namespace std;
const int N=1e5+100;
int n,m,tot,cnt;
int fa[N],last[N];
int son[N],deep[N],dfn[N],num[N],top[N];//重儿子 深度 dfs序 子树规模 所在重链的顶端节点
int sum[N*4],mx[N*4],w[N];
struct orz{
    int v,nex;}e[N];
char op[10];
void init()
{
    cnt=0;
    tot=0;
    memset(last,0,sizeof(last));
    memset(son,-1,sizeof(son));
}
void Insert(int x,int y)
{
    cnt++;
    e[cnt].v=y;
    e[cnt].nex=last[x];
    last[x]=cnt;
}
void dfs1(int x,int d,int pre)
{
    fa[x]=pre;
    deep[x]=d;
    num[x]=1;
    for (int i=last[x];i;i=e[i].nex)
    {
        int v=e[i].v;
        if (v==fa[x]) continue;
        dfs1(v,d+1,x);
        num[x]+=num[v];
        if (son[x]==-1 || num[v]>num[son[x]]) son[x]=v;
    }
}
void dfs2(int x,int sp)
{
    top[x]=sp;
    dfn[x]=++tot;
    if (son[x]==-1) return ;
    dfs2(son[x],sp);
    for (int i=last[x];i;i=e[i].nex)
    {
        int v=e[i].v;
        if (v==fa[x]) continue;
        if (v!=son[x]) dfs2(v,v);
    }
}
void PushUp(int s)
{
    sum[s]=sum[s<<1]+sum[s<<1|1];
    mx[s]=max(mx[s<<1],mx[s<<1|1]);
}
void build(int s,int l,int r)
{
    mx[s]=sum[s]=0;
    if (l==r) return ;
    int m=(l+r)>>1;
    build(s<<1,l,m); build(s<<1|1,m+1,r);
    PushUp(s);
}
void update(int s,int l,int r,int pos,int val)
{
    if (l==r)
    {
        mx[s]=sum[s]=val;
        return ;
    }
    int mid=(l+r)>>1;
    if (pos<=mid) update(s<<1,l,mid,pos,val);
    else update(s<<1|1,mid+1,r,pos,val);
    PushUp(s);
}
int querymx(int s,int l,int r,int L,int R)
{
    //printf("s=%d,l=%d,r=%d,L=%d,R=%d\n",s,l,r,L,R);
    if (L<=l&&r<=R) return mx[s];
    int mid=(l+r)>>1;
    int ans=INT_MIN;
    if (L<=mid) ans=max(ans,querymx(s<<1,l,mid,L,R));
    if (R>mid) ans=max(ans,querymx(s<<1|1,mid+1,r,L,R));
    return ans;
}
int querysum(int s,int l,int r,int L,int R)
{
    if (L<=l&&r<=R) return sum[s];
    int mid=(l+r)>>1;
    int ans=0;
    if (L<=mid) ans+=querysum(s<<1,l,mid,L,R);
    if (R>mid) ans+=querysum(s<<1|1,mid+1,r,L,R);
    return ans;
}
void solve(int op,int x, int y)
{
    if (op==1)
    {
        int mx=INT_MIN;
        while (top[x]!=top[y])
        {
            if (deep[top[x]]<deep[top[y]]) swap(x, y);
            mx=max(mx,querymx(1,1,n,dfn[top[x]],dfn[x]));
            x=fa[top[x]];
        }
        if (deep[x]>deep[y]) swap(x,y);
        mx=max(mx,querymx(1,1,n,dfn[x],dfn[y]));
        printf("%d\n",mx);
    }
    else
    {
        int ans=0;
        while (top[x]!=top[y])
        {
            if (deep[top[x]]<deep[top[y]]) swap(x, y);
            ans+=querysum(1,1,n,dfn[top[x]],dfn[x]);
            x=fa[top[x]];
        }
        if (deep[x]>deep[y]) swap(x,y);
        ans+=querysum(1,1,n,dfn[x],dfn[y]);
        printf("%d\n",ans);
    }
}

int main()
{
    while (scanf("%d",&n)!=EOF)
    {
        init();
        int u,v;
        for (int i=1;i<n;i++)
        {
            scanf("%d%d",&u,&v);
            Insert(u,v);
            Insert(v,u);
        }
        dfs1(1,0,0); //cout<<'*'<<endl;
        dfs2(1,1);

        build(1,1,n);
        for (int i=1;i<=n;i++)
        {
            scanf("%d",&u);
            update(1,1,n,dfn[i],u);
        }
        scanf("%d",&m);

        while (m--)
        {
            scanf("%s",op);
            if (op[0]=='C')
            {
                scanf("%d%d",&u,&v);
                update(1,1,n,dfn[u],v);
            }
            else
            {
                scanf("%d%d",&u,&v);
                if (op[1]=='M') solve(1,u,v);
                else solve(2,u,v);
            }
        }
    }
    return 0;
}
View Code

 

posted @ 2019-08-03 10:19  特特w  阅读(225)  评论(0编辑  收藏  举报