[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<cmath>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=2000001;
struct node{ 
    int to,next;
}e[N] ;
int head[N],num,ch[N],n,m;
int lazy[N],sum[N],maxn[N];
int size[N],dep[N],son[N],fa[N],tot,l[N],a[N],top[N];
char ss[11];
void add(int from,int to)
{     num++;
    e[num].to=to;
    e[num].next=head[from];
    head[from]=num;
}
void build(int root,int l,int r)
{
    if(l==r)
    {
        //cout<<a[l]<<endl;
        maxn[root]=a[l];
        sum[root]=a[l];
        return ;
    }
    int mid=(l+r)>>1;
    build(root<<1,l,mid);
    build(root<<1|1,mid+1,r);
    sum[root]=sum[root<<1]+sum[root<<1|1];
    maxn[root]=max(maxn[root<<1],maxn[root<<1|1]);
    return ;
}


void update(int root,int left,int right,int l,int r,int k)
{
    if(l>right||r<left)return ;
    if(l<=left&&right<=r)
    {
        sum[root]=k;
        //lazy[root]=k;
        maxn[root]=k;
        return ;
    }
    int mid=(left+right)>>1;
    //if(lazy[root])push(root,left,right);
    if(mid>=l) update(root<<1,left,mid,l,r,k);
    if(mid<r)  update(root<<1|1,mid+1,right,l,r,k);
    sum[root]=sum[root<<1]+sum[root<<1|1];
    maxn[root]=max(maxn[root<<1],maxn[root<<1|1]);
    return ;
}

int query1(int root,int left,int right,int l,int r)
{
    if(l>right||r<left)return 0;
    if(l<=left&&r>=right)return sum[root];
    int mid=(left+right)>>1;
    int a=0,b=0;
    if(mid>=l) a=query1(root<<1,left,mid,l,r);
    if(mid<r)  b=query1(root<<1|1,mid+1,right,l,r);
    return a+b;
}

int query2(int root,int left,int right,int l,int r)
{
    int ans=-1e8;
    if(l>right||r<left)return -1e8;
    if(l<=left&&r>=right)return maxn[root];
    int mid=(left+right)>>1;
    int a=-1e8,b=-1e8;
    if(mid>=l) a=query2(root<<1,left,mid,l,r);
    if(mid<r)  b=query2(root<<1|1,mid+1,right,l,r);
    return ans=max(ans,max(a,b));
}
void dfs1(int x)
{
    size[x]=1;
    for(int i=head[x];i;i=e[i].next)
    {
        int v=e[i].to;
        if(!dep[v])
        {
            dep[v]=dep[x]+1;
            fa[v]=x;
            dfs1(v);
            size[x]+=size[v];
            if(size[v]>size[son[x]])son[x]=v;
        }
    }
    return ;
}

void dfs2(int x,int t)
{

    l[x]=++tot;a[tot]=ch[x];top[x]=t;
    if(son[x])dfs2(son[x],t);
    for(int i=head[x];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v!=fa[x]&&v!=son[x])
        dfs2(v,v);
    }
    return ;
}

int cap(int x,int y,int f)
{
    int maxx=0,fx=top[x],fy=top[y];
    if(f==2)maxx=-1e8-9;
    while(fx!=fy)
    {
        if(dep[fx]<dep[fy])
        {
            swap(x,y);swap(fx,fy);
        }
        if(f==1)maxx+=query1(1,1,n,l[fx],l[x]);
        else maxx=max(maxx,query2(1,1,n,l[fx],l[x]));
        x=fa[fx];fx=top[x];
       
    }
    if(dep[x]>dep[y])swap(x,y);
    if(f==1)maxx+=query1(1,1,n,l[x],l[y]);
    else maxx=max(query2(1,1,n,l[x],l[y]),maxx);

    return maxx;
}

int read()
{
    int x=0,w=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*w;
}

int main()
{
    memset(maxn,-127,sizeof(maxn));
    n=read();
    for(int i=1;i<n;i++)
    {
        int x,y;x=read();y=read();
        add(x,y);add(y,x);
    }
    for(int i=1;i<=n;i++)
    {
        ch[i]=read();
    }

    fa[1]=1;
    dep[1]=1;
    dfs1(1);
    dfs2(1,1);

    build(1,1,n);
    m=read();int x,y;
    for(int i=1;i<=m;i++)
    {
        scanf("%s",ss);
        if(ss[0]=='C')
        {
            x=read();y=read();
            update(1,1,n,l[x],l[x],y);
        }
        else if(ss[1]=='M')
        {
            x=read();y=read();
            printf("%d\n",cap(x,y,2));
        }
        else 
        {
            x=read();y=read();
            printf("%d\n",cap(x,y,1));
        }
    }
    return 0;
}

 

posted @ 2018-04-10 17:12  Epiphyllum_thief  阅读(178)  评论(0编辑  收藏  举报