bzoj1036: [ZJOI2008]树的统计Count

http://www.lydsy.com/JudgeOnline/problem.php?id=1036

 

树链剖分板子题

 

#include<cstdio>
#include<iostream>
#include<algorithm>

#define N 30001

using namespace std;

int front[N],to[N<<1],nxt[N<<1],tot;

int n,val[N];

int siz[N],fa[N],dep[N];

int id[N],dy[N],bl[N];

int mx[N<<2],sum[N<<2];

int ans;

void read(int &x)
{
    x=0; int f=1; char c=getchar();
    while(!isdigit(c)) { if(c=='-') f=-1; c=getchar(); }
    while(isdigit(c)) { x=x*10+c-'0'; c=getchar(); }
    x*=f;
}

void add(int u,int v)
{
    to[++tot]=v; nxt[tot]=front[u]; front[u]=tot;
    to[++tot]=u; nxt[tot]=front[v]; front[v]=tot;
}

void dfs1(int x,int y)
{
    siz[x]=1;
    for(int i=front[x];i;i=nxt[i])
        if(to[i]!=y)
        {
            dep[to[i]]=dep[x]+1;
            fa[to[i]]=x;
            dfs1(to[i],x);
            siz[x]+=siz[to[i]];
        }
}

void dfs2(int x,int top)
{
    bl[x]=top;
    id[x]=++tot; dy[tot]=x;
    int y=0;
    for(int i=front[x];i;i=nxt[i])
    {
        if(to[i]==fa[x]) continue;
        if(siz[to[i]]>siz[y]) y=to[i];
    }
    if(y) dfs2(y,top);
    for(int i=front[x];i;i=nxt[i])
    {
        if(to[i]==fa[x] || to[i]==y) continue;
        dfs2(to[i],to[i]); 
    }
} 

void build(int k,int l,int r)
{
    if(l==r)
    {
        mx[k]=sum[k]=val[dy[l]];
        return;
    }
    int mid=l+r>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    mx[k]=max(mx[k<<1],mx[k<<1|1]);
    sum[k]=sum[k<<1]+sum[k<<1|1];
}

void change(int k,int l,int r,int pos,int w)
{
    if(l==r)
    {
        mx[k]=sum[k]=w;
        return;
    }
    int mid=l+r>>1;
    if(pos<=mid) change(k<<1,l,mid,pos,w);
    else change(k<<1|1,mid+1,r,pos,w);
    mx[k]=max(mx[k<<1],mx[k<<1|1]);
    sum[k]=sum[k<<1]+sum[k<<1|1]; 
}

void query(int k,int l,int r,int opl,int opr,bool ty)
{
    if(l>=opl && r<=opr)
    {
        if(!ty) ans=max(ans,mx[k]);
        else ans+=sum[k];
        return;
    }
    int mid=l+r>>1;
    if(opl<=mid) query(k<<1,l,mid,opl,opr,ty);
    if(opr>mid) query(k<<1|1,mid+1,r,opl,opr,ty);
}

void solve(int u,int v,bool ty)
{
    if(!ty) ans=-1e7; 
    else ans=0;
    while(bl[u]!=bl[v])
    {
        if(dep[bl[u]]<dep[bl[v]]) swap(u,v);
        query(1,1,n,id[bl[u]],id[u],ty);
        u=fa[bl[u]];
    }
    if(dep[u]>dep[v]) swap(u,v);
    query(1,1,n,id[u],id[v],ty);
    cout<<ans<<'\n';
} 

int main()
{
    int u,v;  read(n);
    for(int i=1;i<n;++i) read(u),read(v),add(u,v);
    for(int i=1;i<=n;++i) read(val[i]);
    dfs1(1,0); tot=0; dfs2(1,1);
    build(1,1,n);
    int m; char c[7];  read(m);
    while(m--)
    {
        scanf("%s",c);
        read(u); read(v);
        if(c[0]=='C') change(1,1,n,id[u],v);
        else if(c[1]=='M')  solve(u,v,0);
        else solve(u,v,1);
    }
}

 

1036: [ZJOI2008]树的统计Count

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 19421  Solved: 7912
[Submit][Status][Discuss]

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
posted @ 2017-11-28 21:56  TRTTG  阅读(218)  评论(0编辑  收藏  举报