[SDOI2014]旅行

题目描述

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,并记下了途中留宿过的城市的评级最大值。

由于年代久远,旅行者记下的数字已经遗失了,但记录开始之前每座城市的信仰与评级,还有事件记录本身是完好的。请根据这些信息,还原旅行者记下的数字。 为了方便,我们认为事件之间的间隔足够长,以致在任意一次旅行中,所有城市的评级和信仰保持不变。

输入格式

输入的第一行包含整数N,Q依次表示城市数和事件数。

接下来N行,第i+l行两个整数Wi,Ci依次表示记录开始之前,城市i的评级和信仰。 接下来N-1行每行两个整数x,y表示一条双向道路。

接下来Q行,每行一个操作,格式如上所述。

输出格式

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


遇到这种貌似要开n棵线段树,每棵要存n个节点,消耗无数空间的东西时,权值线段树,你值得拥有

这道题就是把正常线段树改成权值线段树就水了

#include<bits/stdc++.h>
#define re return
#define inc(i,l,r) for(int i=l;i<=r;++i)
using namespace std;
template<typename T>inline void rd(T&x)
{
    char c;bool f=0;
    while((c=getchar())<'0'||c>'9')if(c=='-')f=1;
    x=c^48;
    while((c=getchar())>='0'&&c<='9')x=x*10+(c^48);
    if(f)x=-x;
}

const int maxn=500005;
int n,m,tot,k,cnt,hd[maxn];
int T[maxn],Faith[maxn],val[maxn];
int son[maxn],size[maxn],fa[maxn],top[maxn],deep[maxn];
int pos[maxn];

struct node{
    int to,nt;
}e[maxn*2]; 
inline void add(int x,int y)
{
    e[++k].to=y;e[k].nt=hd[x];hd[x]=k;
    e[++k].to=x;e[k].nt=hd[y];hd[y]=k;
}
//----------------------------------树链剖分--------------------------------------
inline void dfs1(int x)
{
    deep[x]=deep[fa[x]]+1;
    size[x]=1;
    if(x==43426)
    cnt=1;
    for(int i=hd[x];i;i=e[i].nt)
    {
        int v=e[i].to;
        if(v==fa[x])continue;
        fa[v]=x;
        dfs1(v);
        size[x]+=size[v];
        if(size[v]>size[son[x]])
        son[x]=v;
    }
}


inline void dfs2(int x,int ftop)
{
    top[x]=ftop;
    pos[x]=++tot;
    if(son[x])
        dfs2(son[x],ftop);//重链剖分 
    for(int i=hd[x];i;i=e[i].nt)
    {
        int v=e[i].to;
        if(!top[v])dfs2(v,v);
    }
}

//--------------------------------------权值线段树---------------------------------------

int ans_sum,ans_max;
int sum[maxn<<5],ls[maxn<<5],rs[maxn<<5],maxx[maxn<<5];
//权值线段树要开2*logn 

inline void pushup(int rt)
{
    sum[rt]=sum[ls[rt]]+sum[rs[rt]];
    maxx[rt]=max(maxx[ls[rt]],maxx[rs[rt]]);
}

inline void add(int &rt,int l,int r,int p,int x)
//将p位置的值修改为X 
{
    if(!rt)//没有访问过 
    rt=++cnt;
    if(l==r)
    {
        maxx[rt]=sum[rt]=x;//赋值 
        re;
    }
    int mid=(l+r)>>1;
    if(p<=mid)add(ls[rt],l,mid,p,x);
    else add(rs[rt],mid+1,r,p,x);
    pushup(rt);//总结 
}

inline void query(int &rt,int l,int r,int x,int y)
//查询x~y的值 
{
    if(!rt)re ;//没有被访问过,其值一定为0,不用访问下去,结束 
    if(x<=l&&r<=y)
    {
        ans_sum+=sum[rt];
        ans_max=max(maxx[rt],ans_max);
        re ;
    }
    int mid=(l+r)>>1;
    if(x<=mid)query(ls[rt],l,mid,x,y);
    if(y>mid) query(rs[rt],mid+1,r,x,y);
} 

int main()
{
    int x,y;
    rd(n),rd(m);
    inc(i,1,n)
    {
        rd(val[i]);//等级 
        rd(Faith[i]); //信仰 
    }
    
    inc(i,2,n)
    {
        rd(x),rd(y);
        add(x,y);
    }
    
    dfs1(1);
    dfs2(1,1);
    
    //build()权值线段树版 
    inc(i,1,n)
    add(T[Faith[i]],1,maxn,pos[i],val[i]);
    
    int cnt=0;
    char opt[5];
    inc(i,1,m)
    {
        scanf("%s",opt);
        rd(x),rd(y); 
        //查询 
        if(opt[0]=='Q')
        {
            ans_sum=ans_max=0;
            int c=Faith[y];
            
            while(top[x]!=top[y])
            {
                if(deep[top[x]]<deep[top[y]])
                    swap(x,y);
                query(T[c],1,maxn,pos[top[x]],pos[x]);
                x=fa[top[x]];
            }
            
            if(deep[x]>deep[y])swap(x,y);
            query(T[c],1,maxn,pos[x],pos[y]);
            
            if(opt[1]=='S')printf("%d\n",ans_sum);
            else printf("%d\n",ans_max);
        }
        //修改 
        else
        {
            if(opt[1]=='C')
            {
                //改信仰 
                add(T[Faith[x]],1,maxn,pos[x],0);
                Faith[x]=y;
                add(T[Faith[x]],1,maxn,pos[x],val[x]);
            }
            else 
            {
                //改等级 
                val[x]=y;
                add(T[Faith[x]],1,maxn,pos[x],val[x]);
            }
        }
    } 
    re 0;
}

 

 

 

posted @ 2019-08-23 15:24  凉如水  阅读(154)  评论(0编辑  收藏  举报