【Luogu】U16325小奇的花园(树链剖分)

  题目链接

  学了学动态开点的树链剖分,其实跟动态开点的线段树差不多啦

  查询的时候别ssbb地动态开点,如果没这个点果断返回0就行

  只要注意花的种类能到intmax就行qwq!!!!

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#include<cstdlib>
#include<map>
#define mid ((l+r)>>1)
#define maxn 100010
#define check(x) if(x==0) x=++tot;
using namespace std;
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch==‘-‘)    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-‘0‘;
        ch=getchar();
    }
    return num*f;
}

int tot;
map<int,int> root;
int ls[maxn*100];
int rs[maxn*100];
int q[maxn];
int size[maxn];
int top[maxn];
int son[maxn];
int father[maxn];
int dfn[maxn];
int deep[maxn];
int back[maxn],cnt;
int n,m;

struct Edge{
    int next,to;
}edge[maxn*3];
int head[maxn],num;
inline void add(int from,int to){
    edge[++num]=(Edge){head[from],to};
    head[from]=num;
}

void find(int x,int fa){
    size[x]=1;    deep[x]=deep[fa]+1;
    for(int i=head[x];i;i=edge[i].next){
        int to=edge[i].to;
        if(to==fa)    continue;
        father[to]=x;
        find(to,x);
        size[x]+=size[to];
        if(son[x]==0||size[son[x]]<size[to])    son[x]=to;
    }
}

void unionn(int x,int Top){
    top[x]=Top;    dfn[x]=++cnt;    back[cnt]=x;
    if(son[x]==0)    return;
    unionn(son[x],Top);
    for(int i=head[x];i;i=edge[i].next){
        int to=edge[i].to;
        if(to==father[x]||to==son[x])    continue;
        unionn(to,to);
    }
    return;
}

inline void pushup(int rt){    tree[rt]=tree[ls[rt]]+tree[rs[rt]];    }

void update(int o,int num,int l,int r,int &rt){
    check(rt);
    if(l==r){
        tree[rt]+=num;
        return;
    }
    if(o<=mid)    update(o,num,l,mid,ls[rt]);
    else        update(o,num,mid+1,r,rs[rt]);
    pushup(rt);
}

int query(int from,int to,int l,int r,int &rt){
    if(rt==0)    return 0;
    if(from<=l&&to>=r)    return tree[rt];
    int ans=0;
    if(from<=mid)    ans+=query(from,to,l,mid,ls[rt]);
    if(to>mid)        ans+=query(from,to,mid+1,r,rs[rt]);
    return ans;
}

inline void addcol(int pos,int val){
    update(dfn[pos],-1,1,n,root[q[pos]]);
    update(dfn[pos],1,1,n,root[val]);
    q[pos]=val;
}

int ask(int from,int to,int val){
    int ans=0;
    while(top[from]!=top[to]){
        if(deep[top[from]]<deep[top[to]])    swap(from,to);
        ans+=query(dfn[top[from]],dfn[from],1,n,root[val]);
        from=father[top[from]];
    }
    if(deep[from]>deep[to])    swap(from,to);
    ans+=query(dfn[from],dfn[to],1,n,root[val]);
    return ans;
}

int main(){
    n=read(),m=read();
    for(int i=1;i<=n;++i)    q[i]=read();
    for(int i=1;i<n;++i){
        int from=read(),to=read();
        add(from,to);
        add(to,from);
    }
    find(1,1);
    unionn(1,1);
    for(int i=1;i<=n;++i)    update(dfn[i],1,1,n,root[q[i]]);
    int last=0;
    for(int i=1;i<=m;++i){
        char c[10];int x,y;
        scanf("%s",c);
        if(c[0]==‘C‘){
            x=read()^last,y=read()^last;
            addcol(x,y);
        }
        else{
            x=read()^last,y=read()^last;
            int z=read()^last;
            last=ask(x,y,z);
            printf("%d\n",last);
        }
    }
    return 0;
}

原文地址:https://www.cnblogs.com/cellular-automaton/p/8352260.html

时间: 2024-10-01 09:37:20

【Luogu】U16325小奇的花园(树链剖分)的相关文章

Luogu P2146 软件包管理器(树链剖分+线段树)

题意 给定\(n\)个软件包,每个软件包都有一个依赖软件包,安装一个软件包必须安装他的依赖软件包,卸载一个软件包必须先卸载所有依赖于它的软件包.给定\(m\)此操作,每次一个操作\(install/unistall\)表示安装或者卸载. 题解 可以通过简单画图看出,在这个树形结构的依赖层次图上,安装一个包相当于安装其到根节点路径上的所有包,删除一个包相当于删除其与其子树的包.用一个重链剖分+线段树处理一下就行了. #include <cstdio> #include <algorithm

【Luogu】P3313旅行(树链剖分)

题目链接 动态开点的树链剖分qwq. 跟小奇的花园一模一样,不做过多讲解. #include<cstdio> #include<cstring> #include<cctype> #include<cstdlib> #include<algorithm> #define maxn 100010 #define mid ((l+r)>>1) #define check(x) if(x==0) x=++tot; using namespa

小奇的花园

[问题描述]小奇的花园有 n 个温室,标号为 1 到 n,温室以及以及温室间的双向道路形成一棵树.每个温室都种植着一种花,随着季节的变换,温室里的花的种类也在不断发生着变化.小奇想知道从温室 x 走到温室 y 的路径中(包括两个端点),第 t 种花出现的次数.[输入格式]第一行为两个整数 n,q,表示温室的数目和操作的数目.第二行有 n 个整数 T 1 ,T 2 ...T n 其中 T i 表示温室 i 中的花的种类.接下来 n-1 行,每个两个整数 x, y,表示温室 x 和 y 之间有一条双

luogu题解P2486[SDOI2011]染色--树链剖分+trick

题目链接 https://www.luogu.org/problemnew/show/P2486 分析 看上去又是一道强行把序列上问题搬运到树上的裸题,然而分析之后发现并不然... 首先我们考虑如何在序列上维护信息:从最简单的想起,如果两个相邻的元素合并,显然是这两个元素所含颜色段个数(其实就是1)加起来,如果两个元素颜色相同就减1;那么两个分别含有两个元素的相邻区间合并,还是把这两个区间所含颜色段个数加起来,如果左区间最右边的颜色等于右区间最左边的颜色就减去1. 如此我们已经得到线段树维护信息

[luogu P3384] [模板]树链剖分

[luogu P3384] [模板]树链剖分 题目描述 如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作: 操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z 操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和 操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z 操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和 输入输出格式 输入格式: 第一行包含4个正整数

Luogu P3384 【模板】树链剖分

传送门~ 树链剖分,顾名思义,就是把树分成链. 通过这个方法,可以优化对树上两点间路径.某一点子树的修改和查询的操作,等. 流程 $dfs1()$ 在这个函数中,要处理出每个节点的: 深度dep[] 父亲fa[] 大小siz[] 重儿子编号hson[] 一个节点的siz[],是包括它自己.它的儿子.它儿子的儿子……一共的节点数量. 所谓的重儿子,就是一个节点的儿子中,siz[]最大的那一个. 叶子节点没有儿子,所以也没有重儿子. 这个函数就是普通的遍历整棵树,每到一个点记录dpth[],siz[

树链剖分+线段树 HDOJ 4897 Little Devil I(小恶魔)

题目链接 题意: 给定一棵树,每条边有黑白两种颜色,初始都是白色,现在有三种操作: 1 u v:u到v路径(最短)上的边都取成相反的颜色 2 u v:u到v路径上相邻的边都取成相反的颜色(相邻即仅有一个节点在路径上) 3 u v:查询u到v路径上有多少个黑色边 思路: 对树进行树链剖分,分成重链和轻链,用两棵线段树W,L来维护.W维护树上在重链上的u和v之间的边的翻转情况(操作在线段树上的[pos[v],pos[u]]区间):L维护树上在重链上的u和v之间的相邻边的翻转情况.那么某一个点u与它父

【Luogu P3384】树链剖分模板

树链剖分的基本思想是把一棵树剖分成若干条链,再利用线段树等数据结构维护相关数据,可以非常暴力优雅地解决很多问题. 树链剖分中的几个基本概念: 重儿子:对于当前节点的所有儿子中,子树大小最大的一个儿子就是重儿子(子树大小相同的则随意取一个) 轻儿子:不是重儿子就是轻儿子 重边:连接父节点和重儿子的边 轻边:连接父节点和轻儿子的边 重链:相邻重边相连形成的链 值得注意的还有以下几点: 叶子节点没有重儿子也没有轻儿子: 对于每一条重链,其起点必然是轻儿子: 单独一个轻叶子节点也是一条重链: 结合上面三

树链剖分简(单)介(绍)

树链剖分可以算是一种数据结构(一大堆数组,按照这个意思,主席树就是一大堆线段树).将一棵树分割成许多条连续的树链,方便完成一下问题: 单点修改(dfs序可以完成) 求LCA(各种乱搞也可以) 树链修改(修改任意树上两点之间的唯一路径) 树链查询 (各种操作)  前两个内容可以用其他方式解决,但是下面两种操作倍增.st表,dfs序就很难解决(解决当然可以解决,只是耗时长点而已).下面开始步入正题. 树链剖分的主要目的是分割树,使它成一条链,然后交给其他数据结构(如线段树,Splay)来进行维护.常