数树数

数树数

题目描述

 

      给定一棵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
#include
#include
#include
#include
#include
#include
#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];
mapl;
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

 

你可能感兴趣的:(树链剖分,线段树)