4771: 七彩树 主席树

  

题意:给定一棵树  每个结点有一个颜色 然后又m个询问

询问:x d   问x的子树内不超过dep[x]+d 深度的子树结点一共有多少个颜色?

1、可以先将问题简化为问整个子树内有多少个不同的颜色

   暴力解法树套树  但是可以用一个技巧来快速维护: 一个颜色一个颜色地处理  把所有相同颜色的点按照dfs序排序,每个点给自己的位置贡献1,相邻的两个点给lca贡献−1。然后只要区间内存在这种颜色,则其子树内的权值和必定为1。那么只需要这样子染好所有颜色之后询问子树和。

  所以如果问题是这样的话只要一个线段树和一个树剖就可以完美的解决了!

2、回到当前的问题  正解是将线段树进化为主席树可持久化地维护即可  主席树的历史版本为深度!!! 所以查询得话就是 qsum(id[x],id[x]+siz[x]-1,1,n,  T[  dep[x]+d] )    (范围为整个子树得编号   树为dep+d得深度得数)

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define ll long long
#define see(x) (cerr<<(#x)<<‘=‘<<(x)<<endl)
#define inf 0x3f3f3f3f
#define CLR(A,v)  memset(A,v,sizeof A)
//////////////////////////////////
const int N=1e6+10;
int T[N],t[N<<5],n,m,ncnt,lson[N<<5],rson[N<<5];
void upnode(int x,int v,int l,int r,int pre,int &pos)
{
    pos=++ncnt;
    lson[pos]=lson[pre];rson[pos]=rson[pre];
    t[pos]=t[pre]+v;
    int m=(l+r)>>1;
    if(l==r)return;
    if(x<=m)upnode(x,v,l,m,lson[pre],lson[pos]);
    else upnode(x,v,m+1,r,rson[pre],rson[pos]);
}
int qsum(int L,int R,int l,int r,int pos)
{
    if(L<=l&&r<=R)return t[pos];
    int ans=0,m=(l+r)>>1;
    if(L<=m)ans+=qsum(L,R,l,m,lson[pos]);
    if(R>m)ans+=qsum(L,R,m+1,r,rson[pos]);
    return ans;
}
/////////////////////////
int tot,id[N],fa[N],top[N],siz[N],son[N],c[N],dep[N],pos,head[N],a,pre[N];
struct Edge{int to,nex;}edge[N<<1];
void add(int a,int b){edge[++pos]=(Edge){b,head[a]};head[a]=pos;}
void dfs1(int x,int f)
{
    fa[x]=f;dep[x]=dep[f]+1;son[x]=0;siz[x]=1;
    for(int i=head[x];i;i=edge[i].nex)
    {
        int v=edge[i].to;
        if(v==f)continue;
        dfs1(v,x);siz[x]+=siz[v];
        if(siz[v]>siz[son[x]])son[x]=v;
    }
}
void dfs2(int x,int topf)
{
    top[x]=topf;id[x]=++tot;pre[tot]=x;
    if(son[x])dfs2(son[x],topf);
    for(int i=head[x];i;i=edge[i].nex)
    {
        int v=edge[i].to;
        if(v==fa[x]||v==son[x])continue;
        dfs2(v,v);
    }
}
int getlca(int x,int y)
{
    while(top[x]!=top[y])
    {
        if(dep[top[x]]<dep[top[y]])swap(x,y);
        x=fa[top[x]];
    }
    return dep[x]>dep[y]?y:x;
}
///////////////////////////
set<int>s[N];
set<int>::iterator t1,t2,t3;
int p[N];

bool cmp(int a,int b){return dep[a]<dep[b];}

int main()
{
    int cas;cin>>cas;
    while(cas--)
    {
        scanf("%d%d",&n,&m);
        rep(i,1,n)scanf("%d",&c[i]);
        rep(i,2,n)scanf("%d",&a),add(i,a),add(a,i);
        dfs1(1,0);dfs2(1,1);
        rep(i,1,n)p[i]=i;
        sort(p+1,p+1+n,cmp);
        for(int i=1,j=1;i<=dep[p[n]]&&j<=n;i++)
        {
            T[i]=T[i-1];
            while(j<=n&&dep[p[j]]==i)
            {
                int x=p[j],idx=id[x];
                s[c[x]].insert(id[x]);
                t2=s[c[x]].find(id[x]);
                t1=t2;t1--;
                t3=t2;t3++;
                upnode(id[x],1,1,n,T[i],T[i]);
                if(t2!=s[c[x]].begin())upnode(id[getlca(x,pre[*t1])],-1,1,n,T[i],T[i]);//,printf("1 lca=%d id=%d ",getlca(x,pre[*t1]),id[getlca(x,pre[*t1])]);
                if(t3!=s[c[x]].end())upnode(id[getlca(x,pre[*t3])],-1,1,n,T[i],T[i]);//,printf("2 lca=%d id=%d\n",getlca(x,pre[*t3]),id[getlca(x,pre[*t3])]);
                if(t2!=s[c[x]].begin()&&t3!=s[c[x]].end())
                upnode(id[getlca(pre[*t1],pre[*t3])],1,1,n,T[i],T[i]);//,printf("lca=%d id=%d\n",getlca(pre[*t1],pre[*t3]),id[getlca(pre[*t1],pre[*t3])]);
                j++;
            }
        }
        int x,y,ans=0;
        while(m--)
        scanf("%d%d",&x,&y),x^=ans,y^=ans,printf("%d\n",ans=qsum(id[x],id[x]+siz[x]-1,1,n,T[ min(dep[p[n]],dep[x]+y)]));
        CLR(head,0);pos=0;
        rep(i,1,n)s[c[i]].clear();
        ncnt=tot=0;
    }
    return 0;
}

原文地址:https://www.cnblogs.com/bxd123/p/11559618.html

时间: 2024-10-12 15:30:05

4771: 七彩树 主席树的相关文章

hdu 2665 可持久化线段树求区间第K大值(函数式线段树||主席树)

http://acm.hdu.edu.cn/showproblem.php?pid=2665 Problem Description Give you a sequence and ask you the kth big number of a inteval. Input The first line is the number of the test cases. For each test case, the first line contain two integer n and m (

可持久化线段树--主席树

浅谈可持久化线段树--主席树 权值线段树 权值线段树和普通线段树不一样的地方就是在于 它的结点存储的是区间内数的个数 这个线段树的好处就在于我们可以根据 左子树 和 右子树 的大小从而进行 查找某个数的排名 或者 查找排名为rk的数 可持久化的含义 可持久数据结构主要指的是我们可以查询历史版本的情况并支持插入,利用使用之前历史版本的数据结构来减少对空间的消耗(能够对历史进行修改的是函数式). 主席树的建树过程: 最开始的时候就是一个空树 然后我们再插入一个元素3 再加入一个元素 1 模版一 :求

小结:线段树 &amp; 主席树

概要: 就是用来维护区间信息,然后各种秀智商游戏. 应用: 优化dp.主席树等. 技巧及注意: size值的活用:主席树就是这样来的.支持区间加减,例题和模板:主席树,[BZOJ]1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树),[BZOJ]1901: Zju2112 Dynamic Rankings(区间第k小+树状数组套可持久化线段树(主席树)) 01(就是更新和不更新等这种对立操作)情况:我们就要在各个更新的操作中明白

【BZOJ3439】Kpm的MC密码 trie树+主席树

Description 背景 想Kpm当年为了防止别人随便进入他的MC,给他的PC设了各种奇怪的密码和验证问题(不要问我他是怎么设的...),于是乎,他现在理所当然地忘记了密码,只能来解答那些神奇的身份验证问题了... 描述 Kpm当年设下的问题是这样的: 现在定义这么一个概念,如果字符串s是字符串c的一个后缀,那么我们称c是s的一个kpm串. 系统将随机生成n个由a…z组成的字符串,由1…n编号(s1,s2…,sn),然后将它们按序告诉你,接下来会给你n个数字,分别为k1…kn,对于每 一个k

bzoj 3545&amp;&amp;3551: [ONTAK2010]Peaks &amp;&amp;加强版 平衡树&amp;&amp;并查集合并树&amp;&amp;主席树

3545: [ONTAK2010]Peaks Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 635  Solved: 177[Submit][Status] Description 在Bytemountains有N座山峰,每座山峰有他的高度h_i.有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达的山峰中第k高的山峰,如果无解输出-1. I

[BZOJ4539][HNOI2016]树(主席树)

4539: [Hnoi2016]树 Time Limit: 40 Sec  Memory Limit: 256 MBSubmit: 746  Solved: 292[Submit][Status][Discuss] Description 小A想做一棵很大的树,但是他手上的材料有限,只好用点小技巧了.开始,小A只有一棵结点数为N的树,结点的编号为1,2,-,N,其中结点1为根:我们称这颗树为模板树.小A决定通过这棵模板树来构建一颗大树.构建过程如下:(1)将模板树复制为初始的大树.(2)以下(2

UOJ#218. 【UNR #1】火车管理 线段树 主席树

原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ218.html 题解 如果我们可以知道每次弹出栈之后新的栈顶是什么,那么我们就可以在一棵区间覆盖.区间求和的线段树上完成这个问题. 于是本题的重点转到了如何求新的栈顶. 考虑用一个主席树维护一下每一个时刻每一个位置的栈顶元素的进栈时间,那么新的栈顶就是 当前位置栈顶的进栈时间-1 这时候的栈顶元素,然后这个东西也可以用我们维护的进栈时间来得到,所以我们只需要弄一个支持区间覆盖单点查询历史版本的主席树:这

权值线段树&amp;&amp;可持久化线段树&amp;&amp;主席树

权值线段树 顾名思义,就是以权值为下标建立的线段树. 现在让我们来考虑考虑上面那句话的产生的三个小问题: 1. 如果说权值作为下标了,那这颗线段树里存什么呢? ----- 这颗线段树中, 记录每个值出现的次数 2.权值很大怎么办?数组空间不够啊 ----- 可以先离散化,再记录 3.那权值线段树到底是用来干嘛的呢? ----- 可以快速求出第k小值(其实主要还是为了主席树做铺垫啦) 那第k小值该怎么求呢??? 从树根依次往下 若当前值K大于左儿子的值,则将K-=左儿子的值,然后访问右儿子 若当前

HDU 5790 Prefix(字典树+主席树)

Prefix Time Limit: 2000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 858    Accepted Submission(s): 256 Problem Description Alice gets N strings. Now she has Q questions to ask you. For each question, she wa