[BZOJ3531] [Sdoi2014]旅行

题目描述

Description

S国有N个城市,编号从1到N。城市间用N-1条双向道路连接,满足
从一个城市出发可以到达其它所有城市。每个城市信仰不同的宗教,如飞天面条神教、隐形独角兽教、绝地教都是常见的信仰。为了方便,我们用不同的正整数代表各种宗教, S国的居民常常旅行。旅行时他们总会走最短路,并且为了避免麻烦,只在信仰和他们相同的城市留宿。当然旅程的终点也是信仰与他相同的城市。S国政府为每个城市标定了不同的旅行评级,旅行者们常会记下途中(包括起点和终点)留宿过的城市的评级总和或最大值。
在S国的历史上常会发生以下几种事件:
”CC x c”:城市x的居民全体改信了c教;
”CW x w”:城市x的评级调整为w;
”QS x y”:一位旅行者从城市x出发,到城市y,并记下了途中留宿过的城市的评级总和;
”QM x y”:一位旅行者从城市x出发,到城市y,并记下了途中留宿过
的城市的评级最大值。
由于年代久远,旅行者记下的数字已经遗失了,但记录开始之前每座城市的信仰与评级,还有事件记录本身是完好的。请根据这些信息,还原旅行者记下的数字。
为了方便,我们认为事件之间的间隔足够长,以致在任意一次旅行中,所有城市的评级和信仰保持不变。

Input

输入的第一行包含整数N,Q依次表示城市数和事件数。
接下来N行,第i+l行两个整数Wi,Ci依次表示记录开始之前,城市i的
评级和信仰。
接下来N-1行每行两个整数x,y表示一条双向道路。
接下来Q行,每行一个操作,格式如上所述。

Output

对每个QS和QM事件,输出一行,表示旅行者记下的数字。

Sample Input

5 6
3 1
2 3
1 2
3 3
5 1
1 2
1 3
3 4
3 5
QS 1 5
CC 3 1
QS 1 5
CW 3 3
QS 1 5
QM 2 4

Sample Output

8
9
11
3

HINT

N,Q < =10^5 , C < =10^5
数据保证对所有QS和QM事件,起点和终点城市的信仰相同;在任意时刻,城市的评级总是不大于10^4的正整数,且宗教值不大于C。

题目分析

一眼树剖 但是信息直接上线段树维护空间会炸
那么我们使用动态开点线段树维护每种信仰即可

#include <cstdio>
#include <cstring>
#include <set>
#include <map>
#include <vector>
#include <cmath>
#include <queue>
#include <algorithm>
using namespace std;
int n,m;
int head[100010],to[100010<<1],net[100010<<1];
int tot;
int w[100010],cx[100010];
void add(int x,int y)
{
    net[++tot]=head[x],head[x]=tot,to[tot]=y;
}
int deep[100010],fa[100010],top[100010],size[100010],son[100010];
int number[100010],cnt,color;
struct your
{
    int lson,rson;
    int maxx,sum;
}a[100010*100];
int root[100010];
void update(int l,int r,int dx,int c,int &num)
{
    if(!num) num=++color;
    if(l==r)
    {
        a[num].maxx=a[num].sum=c;
        return ;
    }
    int mid=(l+r)>>1;
    if(dx<=mid) update(l,mid,dx,c,a[num].lson);
    else update(mid+1,r,dx,c,a[num].rson);
    a[num].sum=a[a[num].lson].sum+a[a[num].rson].sum;
    a[num].maxx=max(a[a[num].lson].maxx,a[a[num].rson].maxx);
} 
void dfs(int x)
{
    deep[x]=deep[fa[x]]+1,size[x]=1;
    for(int i=head[x];i;i=net[i])
        if(to[i]!=fa[x])
        {
            fa[to[i]]=x,dfs(to[i]);
            size[x]+=size[to[i]];
            if(size[to[i]]>size[son[x]])
                son[x]=to[i];
        }
}
void dfs2(int x,int temp)
{
    number[x]=++cnt,top[x]=temp;
    update(1,n,number[x],w[x],root[cx[x]]);
    if(son[x]) dfs2(son[x],temp);
    for(int i=head[x];i;i=net[i])
        if(to[i]!=fa[x]&&to[i]!=son[x])
            dfs2(to[i],to[i]);
}
char s[100];
int ask(int dx,int dy,int l,int r,int num,int color)
{
    if(dx<=l&&r<=dy) 
        return (color==1)?a[num].sum:a[num].maxx;
    int mid=(l+r)>>1;
    if(dy<=mid) return ask(dx,dy,l,mid,a[num].lson,color);
    if(dx>mid) return ask(dx,dy,mid+1,r,a[num].rson,color);
    if(color==1) return ask(dx,dy,l,mid,a[num].lson,color)+ask(dx,dy,mid+1,r,a[num].rson,color);
    else return max(ask(dx,dy,l,mid,a[num].lson,color),ask(dx,dy,mid+1,r,a[num].rson,color));
}
int asksum(int x,int y)
{
    int sum=0,z=cx[x];
    while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]]) swap(x,y);
        sum+=ask(number[top[x]],number[x],1,n,root[z],1);
        x=fa[top[x]];
    }
    if(deep[x]>deep[y]) swap(x,y);
    sum+=ask(number[x],number[y],1,n,root[z],1);
    return sum;
}
int askmax(int x,int y)
{
    int sum=0,z=cx[x];
    while(top[x]!=top[y])
    {
        if(deep[top[x]]<deep[top[y]]) swap(x,y);
        sum=max(sum,ask(number[top[x]],number[x],1,n,root[z],2));
        x=fa[top[x]];
    }
    if(deep[x]>deep[y]) swap(x,y);
    sum=max(sum,ask(number[x],number[y],1,n,root[z],2));
    return sum;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++) scanf("%d%d",&w[i],&cx[i]);
    for(int x,y,i=1;i<n;i++)
        scanf("%d%d",&x,&y),add(x,y),add(y,x);
    dfs(1),dfs2(1,1);
    for(int i=1;i<=m;i++)
    {
        scanf("%s",&s[0]);
        if(s[1]=='C')
        {
            int x,y;
            scanf("%d%d",&x,&y);
            update(1,n,number[x],0,root[cx[x]]);
            cx[x]=y;
            update(1,n,number[x],w[x],root[cx[x]]);
        }
           else if(s[1]=='W')
           {
               int x,y;
               scanf("%d%d",&x,&y);
               w[x]=y;
               update(1,n,number[x],w[x],root[cx[x]]);
           }
           else if(s[1]=='S')
           {
               int x,y;
               scanf("%d%d",&x,&y);
               printf("%d\n",asksum(x,y));
           }
           else if(s[1]=='M')
           {
               int x,y;
               scanf("%d%d",&x,&y);
               printf("%d\n",askmax(x,y));
           }
    }
    return 0;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注