BZOJ3531 SDOI2014 旅行

3531: [Sdoi2014]旅行

Time Limit: 40 Sec  Memory Limit: 512 MB
Submit: 3195  Solved: 1428
[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。

https://blog.csdn.net/Clove_unique/article/details/50949317

 

题解:先感谢zyf2000的代码吧,听说“网红”大佬要在大学打ACM就感到很开心啊,虽然我离chemistry很远很远了。很明显的树链剖分+线段树,可是每个城市信仰不同,,如果建1e5颗线段树是无法承受的,于是动态开点的线段树?好吧第一次写。对于每种宗教信仰开一颗线段树,也就是只有每个城市的那一条链。改变信仰是就在旧的信仰那棵树里删掉在新的信仰里加入。写法和主席树还是不一样的,傻傻分不清,我一开始差点把build写成了普通的线段树,,但是大致上类似吧。然后在树剖往上跳的时候切记要存下起点的信仰,否则跳过重链后新的x不一定是这种信仰的城市,像我无脑root[c[x]]的都能过样例,假的吧。至于内存要开多大,感觉和主席树内存是一样的说,但是这里有更改的操作,所以开个40倍?这样这题是能过的。
#include<bits/stdc++.h>
#define ls x<<1
#define rs x<<1|1
#define ll long long 
#define pb push_back
using namespace std;
const int maxn=1e5+100;
int fir[maxn],nxt[maxn*2],to[maxn*2];
int depth[maxn],top[maxn],fa[maxn],siz[maxn],son[maxn],id[maxn];
int w[maxn],root[maxn],c[maxn];
struct node
{
    int l,r;
    int sum,mx;
}no[maxn*40];
int tot=0,cnt=0,cns=0;
void add_e(int x,int y)
{
    ++cnt;nxt[cnt]=fir[x];fir[x]=cnt;to[cnt]=y;
    ++cnt;nxt[cnt]=fir[y];fir[y]=cnt;to[cnt]=x;
}
void dfs1(int x,int f)
{
    depth[x]=depth[f]+1;
    fa[x]=f;
    siz[x]=1;
    int maxx=0;
    fa[x]=f;
    for(int i=fir[x];i;i=nxt[i])
    {
        int v=to[i];
        if(v==f)continue;
        dfs1(v,x);
        siz[x]+=siz[v];
        if(siz[v]>maxx)
        {
            maxx=siz[v];
            son[x]=v;
        }
    }
}
void dfs2(int x,int f)
{
    top[x]=f;
    id[x]=++tot;
    if(son[x])dfs2(son[x],f);
    for(int i=fir[x];i;i=nxt[i])
    {
        if(to[i]==fa[x]||to[i]==son[x])continue;
        dfs2(to[i],to[i]);
    }
}
void push_up(int x)
{
    no[x].sum=no[no[x].l].sum+no[no[x].r].sum;
    no[x].mx=max(no[no[x].l].mx,no[no[x].r].mx);
}
void build(int&x,int l,int r,int v,int pl)
{
    if(!x)x=++cns;
    if(l==r)
    {
        no[x].sum=no[x].mx=v;
        return;
    }
    int mid=(l+r)>>1;
    if(pl<=mid)build(no[x].l,l,mid,v,pl);
    else build(no[x].r,mid+1,r,v,pl);
    push_up(x);
}
int query_max(int x,int l,int r,int L,int R)
{
    if(L<=l&&r<=R)return no[x].mx;
    int mid=(l+r)>>1;
    int ans=0;
    if(L<=mid)ans=max(ans,query_max(no[x].l,l,mid,L,R));
    if(R>mid)ans=max(ans,query_max(no[x].r,mid+1,r,L,R));
    return ans;     
}
int query_sum(int x,int l,int r,int L,int R)
{
    if(L<=l&&r<=R)return no[x].sum;
    int mid=(l+r)>>1;
    int ans=0;
    if(L<=mid)ans+=query_sum(no[x].l,l,mid,L,R);
    if(R>mid)ans+=query_sum(no[x].r,mid+1,r,L,R);
    return ans;
}
int n,q;
char a[10];
int main()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)scanf("%d%d",&w[i],&c[i]);
    int u,v;
    for(int i=1;i<n;i++){
        scanf("%d%d",&u,&v);add_e(u,v);
    }
    dfs1(1,0);
    dfs2(1,1);
    for(int i=1;i<=n;i++)build(root[c[i]],1,tot,w[i],id[i]);
    for(int i=1;i<=q;i++)
    {
        scanf("%s",a);
        if(a[0]=='C'&&a[1]=='C')
        {
            scanf("%d%d",&u,&v);
            build(root[c[u]],1,tot,0,id[u]);
            build(root[v],1,tot,w[u],id[u]);
            c[u]=v;
        }
        if(a[0]=='C'&&a[1]=='W')
        {
            scanf("%d%d",&u,&v);
            build(root[c[u]],1,tot,v,id[u]);
            w[u]=v;
        }
        if(a[0]=='Q'&&a[1]=='S')
        {
            int x,y;
            scanf("%d%d",&x,&y);
            int ans=0;
            int sr=c[x];//这个地方一定要记录c[x]
            int tx=top[x],ty=top[y];
            while(tx!=ty)
            {
                if(depth[tx]<depth[ty])
                {
                    swap(x,y);swap(tx,ty);
                }
                ans+=query_sum(root[sr],1,tot,id[tx],id[x]);
                x=fa[tx];
                tx=top[x];
            }
            if(id[x]>id[y])swap(x,y);
            ans+=query_sum(root[sr],1,tot,id[x],id[y]);
            cout<<ans<<"\n";
        }
        if(a[0]=='Q'&&a[1]=='M')
        {
            int x,y;
            scanf("%d%d",&x,&y);
            int ans=0;
            int sr=c[x];
            int tx=top[x],ty=top[y];
            while(tx!=ty)
            {
                if(depth[tx]<depth[ty])
                {
                    swap(x,y);swap(tx,ty);
                }
                ans=max(ans,query_max(root[sr],1,tot,id[tx],id[x]));
                x=fa[tx];
                tx=top[x];
            }
            if(id[x]>id[y])swap(x,y);
            ans=max(ans,query_max(root[sr],1,tot,id[x],id[y]));
            cout<<ans<<"\n";
        }
    }
}

  

 
 
 
posted @ 2018-10-01 19:50  Twilight7  阅读(120)  评论(0编辑  收藏  举报