数树数

数树数

题目描述

 

      给定一棵N个节点的树,标号从1~N。每个点有一个权值。要求维护两种操作:

1. C i x(0<=x<2^31) 表示将i点权值变为x

2. Q i j x(0<=x<2^31) 表示询问i到j的路径上有多少个值为x的节点

 

 

输入

 

对于每个测试点,第一行有两个整数N,Q,分别表示树上节点个数询问个数。下面一行N个整数,表示初始时每个点的权值。接下来N-1行,每行两个整数x,y,表示x与y之间有边。接下来Q行,每行表示一个操作,操作的描述已经在题目描述中给出。

 

对于30%的数据,N,Q<=1000;

对于100%的数据,N<=100000,Q<=200000。

 

 

 

 

输出

 

         对于每个Q输出一行所求的答案。

 

 

样例输入

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

样例输出

0
1
1
0

考虑对每个权值开线段树,下标为点的编号

维护点的数目和

修改就把相应的两种权值的树拉出来

查询就树剖+区间查询

树不能开满,那就动态开

似乎很像旅行

#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#define maxn 100005
using namespace std;
int n,T,Q,head[maxn],s[maxn],lsh[maxn*3],dy[maxn*3],t1,t2,tot,fs,total;
int size[maxn],son[maxn],fa[maxn],top[maxn],deep[maxn],sc,dfsn[maxn],fsy,li,ri,root[maxn*3];
map<int,int>l;
char ch;
struct node{
    int v,nex;
}e[maxn*2];
struct no{
    int id,a,b,c;
}q[maxn*2];
struct ff{
    int x,ls,rs,l,r;
}tree[maxn*3*21];
void lj(int t1,int t2){
    total++;e[total].v=t2;e[total].nex=head[t1];head[t1]=total;
}
void Lsh(){
    sort(lsh+1,lsh+tot+1);
    lsh[0]=-1;
    for(int i=1;i<=tot;i++){
        if(lsh[i]!=lsh[i-1])l[lsh[i]]=++fs,dy[fs]=lsh[i];
    }
}
void dfs1(int k,int fath){
    fa[k]=fath;deep[k]=deep[fath]+1;
    int sz=0,gp=-1;
    for(int i=head[k];i;i=e[i].nex){
        if(e[i].v!=fath){
            dfs1(e[i].v,k);
            sz+=size[e[i].v];
            if(gp==-1)gp=e[i].v;
            if(size[e[i].v]>size[gp])gp=e[i].v;
        }
    }
    size[k]=sz+1;son[k]=gp;
}
void dfs2(int k){
    dfsn[k]=++sc;
    if(son[k]!=-1){
        top[son[k]]=top[k];
        dfs2(son[k]);
    }
    for(int i=head[k];i;i=e[i].nex){
        if(e[i].v!=fa[k]&&e[i].v!=son[k]){
            top[e[i].v]=e[i].v;
            dfs2(e[i].v);
        }
    }
}
void wh(int k){
    tree[k].x=tree[tree[k].ls].x+tree[tree[k].rs].x;
}
void lian(int &k,int l,int r,int pl,int v){
    if(!k)k=++fsy;
    tree[k].l=l;tree[k].r=r;
    if(l==r){
        tree[k].x+=v;return;
    }
    int mid=l+r>>1;
    if(pl<=mid)lian(tree[k].ls,l,mid,pl,v);
    else lian(tree[k].rs,mid+1,r,pl,v);
    wh(k);
}
int ask(int k){
    if(!k)return 0;
    if(tree[k].l>=li&&tree[k].r<=ri){
        return tree[k].x;
    }
    int mid=tree[k].l+tree[k].r>>1;
    int co=0;
    if(li<=mid)co+=ask(tree[k].ls);
    if(ri>mid)co+=ask(tree[k].rs);
    return co;
}
int main(){
    cin>>n>>Q;
    for(int i=1;i<=n;i++){
        scanf("%d",&s[i]);
        lsh[++tot]=s[i];
    }
    for(int i=1;i<n;i++){
        scanf("%d%d",&t1,&t2);
        lj(t1,t2);lj(t2,t1);
    }
    for(int i=1;i<=Q;i++){
        scanf(" %c",&ch);
        if(ch=='C'){
            q[i].id=1;
            scanf("%d%d",&q[i].a,&q[i].b);
            lsh[++tot]=q[i].b;
        }
        else {
            scanf("%d%d%d",&q[i].a,&q[i].b,&q[i].c);
            lsh[++tot]=q[i].c;
        }
    }
    Lsh();
    dfs1(1,0);top[1]=1;dfs2(1);
    for(int i=1;i<=n;i++){
        int tmp=l[s[i]];
        lian(root[tmp],1,n,dfsn[i],1);
    }
    for(int i=1;i<=Q;i++){
        if(q[i].id==1){
            int tmp=l[s[q[i].a]];
            lian(root[tmp],1,n,dfsn[q[i].a],-1);
            s[q[i].a]=q[i].b;
            tmp=l[s[q[i].a]];
            lian(root[tmp],1,n,dfsn[q[i].a],1);
        }
        else {
            int sum=0,x,y,tmp;
            x=q[i].a,y=q[i].b;tmp=l[q[i].c];
            t1=top[x],t2=top[y];
            while(t1!=t2){
                if(deep[t1]<deep[t2])swap(x,y),swap(t1,t2);
                li=dfsn[t1];ri=dfsn[x];
                sum+=ask(root[tmp]);
                x=fa[t1];t1=top[x];
            } 
            if(deep[x]<deep[y])swap(x,y);
            li=dfsn[y],ri=dfsn[x];
            sum+=ask(root[tmp]);
            printf("%d
",sum);
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/liankewei/p/10358843.html