BZOJ 4999 This Problem Is Too Simple!

Description

给您一颗树,每个节点有个初始值。
现在支持以下两种操作:
1. C i x(0<=x<2^31) 表示将i节点的值改为x。
2. Q i j x(0<=x<2^31) 表示询问i节点到j节点的路径上有多少个值为x的节点。
 

Input

第一行有两个整数N,Q(1 ≤N≤ 100,000;1 ≤Q≤ 200,000),分别表示节点个数和操作个数。
下面一行N个整数,表示初始时每个节点的初始值。
接下来N-1行,每行两个整数x,y,表示x节点与y节点之间有边直接相连(描述一颗树)。
接下来Q行,每行表示一个操作,操作的描述已经在题目描述中给出。
 

 

Output

对于每个Q输出单独一行表示所求的答案。
 

 

Sample Input

5 6
10 20 30 40 50
1 2
1 3
3 4
3 5
Q 2 3 40
C 1 40
Q 2 3 40
Q 4 5 30
C 3 10
Q 4 5 30

Sample Output

0
1
1
0

 

题解:

  这个题目,树链剖分是十分显然的,但怎么查询权值为x的节点个数呢?

  可以为每个权值都开一棵线段树,当然要动态开点,因为开不下,所以离散化一下就可以了。

 

代码:

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <iostream>
#include <map>
#define MAXN 100010
using namespace std;
struct edge{
    int first;
    int next;
    int to;
}a[MAXN*2];
struct tree{
    int ls,rs,sum;
}tr[5000010];
int dep[MAXN],son[MAXN],size[MAXN],fa[MAXN],top[MAXN],dfn[MAXN],w[MAXN];
int numed=0,numtr=0,numcl=0,numdfn=0,n,q;
int roof[MAXN*3],color[MAXN];
map<int,int> mp;
char s[3];

void addedge(int from,int to){
    a[++numed].to=to;
    a[numed].next=a[from].first;
    a[from].first=numed;
}

void dfs1(int now,int f){
    fa[now]=f,dep[now]=dep[f]+1,size[now]=1;
    for(int i=a[now].first;i;i=a[i].next){
        int to=a[i].to;
        if(to==f) continue;
        dfs1(to,now);
        if(size[to]>size[son[now]]) son[now]=to;
        size[now]+=size[to];
    }
}

void dfs2(int now,int tp){
    top[now]=tp;dfn[now]=++numdfn;
    if(son[now]) dfs2(son[now],tp);
    for(int i=a[now].first;i;i=a[i].next){
        int to=a[i].to;
        if(to==fa[now]||to==son[now]) continue;
        dfs2(to,to);
    }
}

void change(int &x,int l,int r,int pos,int zhi){
    if(!x) x=++numtr;
    if(l==r&&l==pos){
        tr[x].sum+=zhi;
        return;
    }
    int mid=(l+r)/2;
    if(pos<=mid) change(tr[x].ls,l,mid,pos,zhi);
    else change(tr[x].rs,mid+1,r,pos,zhi);
    tr[x].sum=tr[tr[x].ls].sum+tr[tr[x].rs].sum;
}

int query(int x,int L,int R,int l,int r){
    if(!x) return 0;
    if(L==l&&R==r){
        return tr[x].sum;
    }
    int mid=(L+R)/2;
    if(r<=mid) return query(tr[x].ls,L,mid,l,r);
    else if(l>mid) return query(tr[x].rs,mid+1,R,l,r);
    else return query(tr[x].ls,L,mid,l,mid)+query(tr[x].rs,mid+1,R,mid+1,r);
}

int work(int x,int y,int rf){
    int topx=top[x],topy=top[y],ans=0;
    while(topx!=topy){
        if(dep[topx]<dep[topy]) swap(topx,topy),swap(x,y);
        ans+=query(rf,1,n,dfn[topx],dfn[x]);
        x=fa[topx];
        topx=top[x];
    }
    if(dep[x]<dep[y]) swap(x,y);
    ans+=query(rf,1,n,dfn[y],dfn[x]);
    return ans;
}

int main()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++){
        int x;scanf("%d",&x);
        if(!mp[x]) mp[x]=++numcl;
        color[i]=mp[x];
    }
    for(int i=1;i<=n-1;i++){
        int x,y;scanf("%d%d",&x,&y);
        addedge(x,y),addedge(y,x);
    }
    dfs1(1,0),dfs2(1,1);
    for(int i=1;i<=n;i++)
        change(roof[color[i]],1,n,dfn[i],1);
    while(q--){
        scanf("%s",s);
        if(s[0]=='C'){
            int x,y;scanf("%d%d",&x,&y);
            if(!mp[y]) mp[y]=++numcl;
            change(roof[color[x]],1,n,dfn[x],-1);
            color[x]=mp[y];
            change(roof[color[x]],1,n,dfn[x],1);
        }
        else{
            int x,y,z;scanf("%d%d%d",&x,&y,&z);
            if(!mp[z]) mp[z]=++numcl;
            printf("%d\n",work(x,y,roof[mp[z]]));
        }
    }
    return 0;
}

 

posted @ 2017-10-01 11:57  人间失格—太宰治  阅读(447)  评论(0编辑  收藏  举报