1. 程式人生 > >bzoj1036: [ZJOI2008]樹的統計Count(樹鏈剖分+線段樹維護)

bzoj1036: [ZJOI2008]樹的統計Count(樹鏈剖分+線段樹維護)

pro uil AR 總數 include TP ID tdi using


bzoj1036: [ZJOI2008]樹的統計Count

  Time Limit: 10 Sec
  Memory Limit: 162 MB

Description

  一棵樹上有n個節點,編號分別為1到n,每個節點都有一個權值w。我們將以下面的形式來要求你對這棵樹完成一些操作:
  I. CHANGE u t : 把結點u的權值改為t II. QMAX u v: 詢問從點u到點v的路徑上的節點的最大權值 I
  II. 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
  

題目地址:  bzoj1036: [ZJOI2008]樹的統計Count

題目大意:

  題目已經很清楚了
  

題解:

  樹鏈剖分裸題
  
  先把樹輕重鏈剖分(兩遍dfs)
  
  然後線段樹維護區間最大值和區間和
  
  將剖出來的序列合並一下就好了
  


AC代碼

#include <cstdio>
#include <cstring>
#include <algorithm>
#define inf 0x7fffffff
#define N 30005
using namespace std;
int n,Q,cnt,sz;
int w[N],dep[N],size[N],head[N],fa[N];
int pos[N],top[N];
char ch[10];
struct edge{
    int to,next;
}e[N+N];
struct seg{
    int l,r,mx,sum;
}t[N<<2];
void add_edge(int u,int v){
    e[++cnt]=(edge){v,head[u]};head[u]=cnt;
    e[++cnt]=(edge){u,head[v]};head[v]=cnt;
}
void dfs1(int u){
    size[u]=1;
    for(int i=head[u];i;i=e[i].next){
        if(e[i].to==fa[u])continue;
        dep[e[i].to]=dep[u]+1;
        fa[e[i].to]=u;
        dfs1(e[i].to);
        size[u]+=size[e[i].to];
    }
}
void dfs2(int u,int chain){
    int k=0;sz++;
    pos[u]=sz;
    top[u]=chain;
    for(int i=head[u];i;i=e[i].next)
        if(dep[e[i].to]>dep[u]&&size[e[i].to]>size[k])
            k=e[i].to;
    if(k==0)return;
    dfs2(k,chain);
    for(int i=head[u];i;i=e[i].next)
        if(dep[e[i].to]>dep[u]&&k!=e[i].to)
            dfs2(e[i].to,e[i].to);
}
void build(int l,int r,int id){
    t[id].l=l;t[id].r=r;
    if(l==r)return;
    int mid=(l+r)>>1;
    build(l,mid,id<<1);
    build(mid+1,r,id<<1|1);
}
void change(int id,int k,int w){
    int l=t[id].l,r=t[id].r,mid=(l+r)>>1;
    if(l==r){
        t[id].sum=t[id].mx=w;
        return;
    }
    if(k<=mid)change(id<<1,k,w);
    else change(id<<1|1,k,w);
    t[id].sum=t[id<<1].sum+t[id<<1|1].sum;
    t[id].mx=max(t[id<<1].mx,t[id<<1|1].mx);
}
int querysum(int id,int L,int R){
    int l=t[id].l,r=t[id].r,mid=(l+r)>>1;
    if(l==L&&R==r)return t[id].sum;
    if(R<=mid)return querysum(id<<1,L,R);
    else if(L>mid)return querysum(id<<1|1,L,R);
    else return querysum(id<<1,L,mid)+querysum(id<<1|1,mid+1,R);
}
int querymx(int id,int L,int R){
    int l=t[id].l,r=t[id].r,mid=(l+r)>>1;
    if(l==L&&R==r)return t[id].mx;
    if(R<=mid)return querymx(id<<1,L,R);
    else if(L>mid)return querymx(id<<1|1,L,R);
    else return max(querymx(id<<1,L,mid),querymx(id<<1|1,mid+1,R));
}
int solvesum(int a,int b){
    int sum=0;
    while(top[a]!=top[b]){
        if(dep[top[a]]<dep[top[b]])swap(a,b);
        sum+=querysum(1,pos[top[a]],pos[a]);
        a=fa[top[a]];
    }
    if(pos[a]>pos[b])swap(a,b);
    sum+=querysum(1,pos[a],pos[b]);
    return sum;
}
int solvemx(int a,int b){
    int mx=-inf;
    while(top[a]!=top[b]){
        if(dep[top[a]]<dep[top[b]])swap(a,b);
        mx=max(mx,querymx(1,pos[top[a]],pos[a]));
        a=fa[top[a]];
    }
    if(pos[a]>pos[b])swap(a,b);
    mx=max(mx,querymx(1,pos[a],pos[b]));
    return mx;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<n;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        add_edge(u,v);
    }
    for(int i=1;i<=n;i++)scanf("%d",&w[i]);
    dfs1(1);
    dfs2(1,1);
     
    build(1,n,1);
    for(int i=1;i<=n;i++)
        change(1,pos[i],w[i]);
    scanf("%d",&Q);
    while(Q--){
        int x,y;scanf("%s%d%d",ch+1,&x,&y);
        if(ch[1]=='C'){
            w[x]=y;
            change(1,pos[x],y);
        }else
            if(ch[2]=='M')
                printf("%d\n",solvemx(x,y));
            else
                printf("%d\n",solvesum(x,y));
    }
    return 0;
}

bzoj1036: [ZJOI2008]樹的統計Count(樹鏈剖分+線段樹維護)