bzoj3531[Sdoi2014]旅行

Posted wsy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj3531[Sdoi2014]旅行相关的知识,希望对你有一定的参考价值。

3531: [Sdoi2014]旅行

Time Limit: 40 Sec  Memory Limit: 512 MB
Submit: 2640  Solved: 1142
[Submit][Status][Discuss]

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。

Source

Round 1 Day 1

 

树链剖分+动态开点
树链剖分路径转序列后,对每种颜色建立一棵线段树
线段树动态开点,和主席树类似,主要为了节省空间
由于一次操作到底层只可能产生log个节点,所以空间开NlogN
然后就是常规操作

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#define ll long long
#define N 100050
using namespace std;
int n,m,tot,cnt,num,hd[N],tp[N],fa[N],rt[N],dep[N],siz[N],tid[N],son[N],w[N],c[N];
struct node{
    int ls,rs,mx,sum;
    node(){ls=rs=mx=sum=0;}
}t[N*20];
struct edge{int v,next;}e[N<<1];
void adde(int u,int v){
    e[++tot].v=v;
    e[tot].next=hd[u];
    hd[u]=tot;
}
void dfs1(int u,int pre){
    dep[u]=dep[pre]+1;siz[u]=1;fa[u]=pre;
    for(int i=hd[u];i;i=e[i].next){
        int v=e[i].v;
        if(v==pre)continue;
        dfs1(v,u);siz[u]+=siz[v];
        if(siz[v]>siz[son[u]])son[u]=v;
    }
}
void dfs2(int u,int anc){
    if(!u)return;
    tid[u]=++cnt;tp[u]=anc;
    dfs2(son[u],anc);
    for(int i=hd[u];i;i=e[i].next){
        int v=e[i].v;
        if(v==fa[u]||v==son[u])continue;
        dfs2(v,v);
    }
}
void pushup(int u){
    int ls=t[u].ls,rs=t[u].rs;
    t[u].mx=max(t[ls].mx,t[rs].mx);
    t[u].sum=t[ls].sum+t[rs].sum;
}
void update(int &u,int l,int r,int p,int val){
    if(!u)u=++num;if(p>r||p<l)return;
    if(l==r){
        t[u].sum=t[u].mx=val;
        return;
    }
    int mid=l+r>>1;
    update(t[u].ls,l,mid,p,val);
    update(t[u].rs,mid+1,r,p,val);
    pushup(u);
}
int qsum(int u,int L,int R,int l,int r){
    if(!u)return 0;
    if(l<=L&&R<=r)return t[u].sum;
    int mid=L+R>>1,tmp=0;
    if(l<=mid)tmp+=qsum(t[u].ls,L,mid,l,r);
    if(r>mid)tmp+=qsum(t[u].rs,mid+1,R,l,r);
    return tmp;
}
int qmx(int u,int L,int R,int l,int r){
    if(!u)return 0;
    if(l<=L&&R<=r)return t[u].mx;
    int mid=L+R>>1,tmp=0;
    if(l<=mid)tmp=max(tmp,qmx(t[u].ls,L,mid,l,r));
    if(r>mid)tmp=max(tmp,qmx(t[u].rs,mid+1,R,l,r));
    return tmp;
}
int jump(int x,int y,int op){
    int col=c[x],fx=tp[x],fy=tp[y],ret=0;
    while(fx!=fy){
        if(dep[fx]<dep[fy]){
            swap(fx,fy);
            swap(x,y);
        }
        if(op)ret=max(ret,qmx(rt[col],1,cnt,tid[fx],tid[x]));
        else ret+=qsum(rt[col],1,cnt,tid[fx],tid[x]);
        x=fa[fx];fx=tp[x];
    }
    if(dep[x]>dep[y])swap(x,y);
    if(op)ret=max(ret,qmx(rt[col],1,cnt,tid[x],tid[y]));
    else ret+=qsum(rt[col],1,cnt,tid[x],tid[y]);
    return ret;
}

int main(){
    //freopen(".in","r",stdin);
    //freopen(".out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    scanf("%d%d",&w[i],&c[i]);
    for(int i=1;i<n;i++){
        int a,b;
        scanf("%d%d",&a,&b);
        adde(a,b);adde(b,a);
    }
    dfs1(1,0);dfs2(1,1);
    for(int i=1;i<=n;i++)
    update(rt[c[i]],1,cnt,tid[i],w[i]);
    char s[5];int x,y,op;
    while(m--){
        scanf("%s%d%d",s,&x,&y);
        if(s[0]==C){
            if(s[1]==C){
                update(rt[c[x]],1,cnt,tid[x],0);
                update(rt[y],1,cnt,tid[x],w[x]);
                c[x]=y;
            }
            else{
                update(rt[c[x]],1,cnt,tid[x],y);
                w[x]=y;
            }
        }
        else{
            op=s[1]==M?1:0;
            printf("%d\n",jump(x,y,op));
        }
    }
    return  0;
}

以上是关于bzoj3531[Sdoi2014]旅行的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ3531: [Sdoi2014]旅行

BZOJ3531SDOI2014旅行

bzoj 3531 [Sdoi2014]旅行(树链剖分,线段树)

Bzoj3531: [Sdoi2014]旅行

[BZOJ]3531: [Sdoi2014]旅行

BZOJ 3531SDOI 2014旅行 树链剖分