luogu P2590 [ZJOI2008]树的统计

题目描述

一棵树上有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本身

输入输出格式

输入格式:

 

输入文件的第一行为一个整数n,表示节点的个数。

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

接下来一行n个整数,第i个整数wi表示节点i的权值。

接下来1行,为一个整数q,表示操作的总数。

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

 

输出格式:

 

对于每个“QMAX”或者“QSUM”的操作,每行输出一个整数表示要求输出的结果。

 

输入输出样例

输入样例#1:
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
输出样例#1:
4
1
2
2
10
6
5
6
5
16

说明

对于100%的数据,保证1<=n<=30000,0<=q<=200000;中途操作中保证每个节点的权值w在-30000到30000之间。

 树链剖分+线段树维护

#include<cstdio>
#include<algorithm>
using namespace std;
#define maxn 100010
#define inf 0x7fffffff
struct Edge {
    int u,v,next;
    Edge(int u=0,int v=0,int next=0):
        u(u),v(v),next(next) {}
}edge[maxn];
struct Segment_Tree {
    int l,r,sum,Max;
}t[maxn<<2];
int head[maxn],cnt;
int size[maxn],wson[maxn],dad[maxn];
int depth[maxn],top[maxn],w[maxn];
int tpos[maxn],pre[maxn],tot;
inline int input() {
    char c=getchar();
    int x=0,flag=1;
    for(;c<'0'||c>'9';c=getchar())
        if(c=='-') flag=-1;
    for(;c>='0'&&c<='9';c=getchar())
        x=(x<<1)+(x<<3)+c-'0';
    return x*flag;
}
inline void Add_edge(int u,int v) {
    edge[++cnt]=Edge(u,v,head[u]);
    head[u]=cnt;
    edge[++cnt]=Edge(v,u,head[v]);
    head[v]=cnt;
    return;
}
void dfs1(int u,int f) {
    size[u]=1;
    for(int i=head[u];i;i=edge[i].next) {
        int v=edge[i].v;
        if(v==f) continue;
        depth[v]=depth[u]+1;
        dad[v]=u;
        dfs1(v,u);
        size[u]+=size[v];
        if(size[v]>size[wson[u]])
            wson[u]=v;
    }
    return;
}
void dfs2(int u,int chain) {
    tpos[u]=++tot;
    pre[tot]=u;
    top[u]=chain;
    if(wson[u]) dfs2(wson[u],chain);
    for(int i=head[u];i;i=edge[i].next) {
        int v=edge[i].v;
        if(v==dad[u]||v==wson[u]) continue;
        dfs2(v,v);
    }
    return;
}
void UpData(int now) {
    int lc=now<<1,rc=now<<1|1;
    t[now].Max=max(t[lc].Max,t[rc].Max);
    t[now].sum=t[lc].sum+t[rc].sum;
    return;
}
void Build(int now,int L,int R) {
    t[now].l=L,t[now].r=R;
    if(L==R) {
        t[now].sum=w[pre[L]];
        t[now].Max=w[pre[L]];
        return;
    }
    int mid=L+R>>1,lc=now<<1,rc=now<<1|1;
    Build(lc,L,mid);
    Build(rc,mid+1,R);
    UpData(now);
    return;
}
void Modify(int now,int pos,int x) {
    int l=t[now].l,r=t[now].r;
    if(l==r) {
        t[now].Max=x;
        t[now].sum=x;
        return;
    }
    int mid=l+r>>1,lc=now<<1,rc=now<<1|1;
    if(pos<=mid) Modify(lc,pos,x);
    else Modify(rc,pos,x);
    UpData(now);
    return;
}
int Query(int now,int L,int R,bool flag) {
    int l=t[now].l,r=t[now].r;
    int mid=l+r>>1,lc=now<<1,rc=now<<1|1;
    if(flag==1) {
        if(l==L&&R==r) return t[now].sum;
        if(R<=mid) return Query(lc,L,R,1);
        else if(L>mid) return Query(rc,L,R,1);
        else {
            int x=Query(lc,L,mid,1);
            int y=Query(rc,mid+1,R,1);
            return x+y;
        }
    } else {
        if(l==L&&R==r) return t[now].Max;
        if(R<=mid) return Query(lc,L,R,0);
        else if(L>mid) return Query(rc,L,R,0);
        else {
            int x=Query(lc,L,mid,0);
            int y=Query(rc,mid+1,R,0);
            return max(x,y);
        }
    }
    UpData(now);
}
int QSUM(int u,int v) {
    int sum=0;
    while(top[u]!=top[v]) {
        if(depth[top[u]]<depth[top[v]])
            swap(u,v);
        sum+=Query(1,tpos[top[u]],tpos[u],1);
        u=dad[top[u]];
    }
    if(depth[u]<depth[v]) swap(u,v);
    sum+=Query(1,tpos[v],tpos[u],1);
    return sum;
}
int QMAX(int u,int v) {
    int Max=-inf;
    while(top[u]!=top[v]) {
        if(depth[top[u]]<depth[top[v]])
            swap(u,v);
        int t=Query(1,tpos[top[u]],tpos[u],0);
        Max=max(Max,t);
        u=dad[top[u]];
    }
    if(depth[u]<depth[v]) swap(u,v);
    int t=Query(1,tpos[v],tpos[u],0);
    return max(Max,t);
}
int main() {
    int n=input();
    for(int i=1;i<n;i++) {
        int u=input(),v=input();
        Add_edge(u,v);
    }
    for(int i=1;i<=n;i++)
        w[i]=input();
    depth[1]=1;
    dad[1]=1;
    dfs1(1,-1);
    dfs2(1,1);
    Build(1,1,n);
    for(int i=input();i>=1;i--) {
        char op[10];
        int x,y;
        scanf("%s%d%d",op,&x,&y);
        if(op[1]=='H') Modify(1,tpos[x],y);
        if(op[1]=='S') printf("%d\n",QSUM(x,y));
        if(op[1]=='M') printf("%d\n",QMAX(x,y));
    }
    return 0;
}

 

posted @ 2017-07-13 10:48  zzzzx  阅读(186)  评论(0编辑  收藏  举报