题目传送门(内部题66)


输入格式

第一行,一个正整数$n$,一个自然数$q$,一个整数$type$。
第二行,$n$个正整数,代表$a_i$。
接下来$n-1$行,每行两个正整数$u$、$v$,代表树中存在一条边$(u,v)$。
接下来$q$行,每行两个正整数$r$、$k$,然后$k$个正整数$x_1,x_2,...,x_k$。询问中的$p_i=(x_i−1+lastans\times type)\mod n+1$。$lastans$为上一个询问的答案,一开始$lastans=0$。


输出格式

输出$q$行,每行一个自然数,代表对应询问的答案。


输出格式

输出$q$行,每行一个自然数,代表对应询问的答案。


样例

样例输入:

5 7 0
1 2 3 4 5
1 2
2 3
2 4
1 5
1 2 4 5
2 2 4 5
3 2 4 5
4 2 4 5
5 2 4 5
5 1 2
100 3 1 2 5

样例输出:

0
0
1
0
0
3
95


数据范围与提示

保证$type\in \{0,1\},1\leqslant a_i,r\leqslant 10^9,u,v,x_i\in [1,n]$。


题解

可以说是一道树上主席树的板子题(然而当时并不会……)。

显然集合$S$就是所有$p_k$到所有$p_k$的$LCA$之间的所有点。

与普通主席树的区别在于,普通主席树维护的是序列,树上主席树维护的是从当前节点到根节点的这条链。

提取出一段类似树上差分的思想。

时间复杂度:$\Theta(\sum k\log \sum k)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
struct rec{int nxt,to;}e[2000001];
int head[1000001],cnt;
int n,q,type;
int a[1000001];
int que[1000001];
int ans;
int fa[1000001][21],depth[1000001];
int root[20000000],tr[20000000],lson[20000000],rson[20000000],tot;
void add(int x,int y)
{
e[++cnt].nxt=head[x];
e[cnt].to=y;
head[x]=cnt;
}
void insert(int &x,int pre,int l,int r,int w)
{
x=++tot;
tr[x]=tr[pre]+1;
lson[x]=lson[pre];
rson[x]=rson[pre];
if(l==r)return;
int mid=(l+r)>>1;
if(w<=mid)insert(lson[x],lson[pre],l,mid,w);
else insert(rson[x],rson[pre],mid+1,r,w);
}
int askmax(int x,int pre,int l,int r,int L,int R)
{
if(tr[x]==tr[pre])return 0;
if(l==r)return l;
int mid=(l+r)>>1;
int res=0;
if(mid<R)res=askmax(rson[x],rson[pre],mid+1,r,L,R);
if(res)return res;
if(L<=mid)res=askmax(lson[x],lson[pre],l,mid,L,R);
if(res)return res;
return 0;
}
int askmin(int x,int pre,int l,int r,int L,int R)
{
if(tr[x]==tr[pre])return 0;
if(l==r)return l;
int mid=(l+r)>>1;
int res=0;
if(L<=mid)res=askmin(lson[x],lson[pre],l,mid,L,R);
if(res)return res;
if(mid<R)res=askmin(rson[x],rson[pre],mid+1,r,L,R);
if(res)return res;
return 0;
}
void pre_dfs(int x)
{
for(int i=head[x];i;i=e[i].nxt)
{
if(depth[e[i].to])continue;
depth[e[i].to]=depth[x]+1;
insert(root[e[i].to],root[x],1,1e9,a[e[i].to]);
fa[e[i].to][0]=x;
for(int j=1;j<=20;j++)
fa[e[i].to][j]=fa[fa[e[i].to][j-1]][j-1];
pre_dfs(e[i].to);
}
}
int LCA(int x,int y)
{
if(depth[x]>depth[y])swap(x,y);
for(int i=20;i>=0;i--)
if(depth[fa[y][i]]>=depth[x])
y=fa[y][i];
if(x==y)return x;
for(int i=20;i>=0;i--)
if(fa[x][i]!=fa[y][i])
{
x=fa[x][i];
y=fa[y][i];
}
return fa[x][0];
}
int main()
{
scanf("%d%d%d",&n,&q,&type);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
for(int i=1;i<n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v);add(v,u);
}
insert(root[1],0,1,1e9,a[1]);
depth[1]=1;
pre_dfs(1);
while(q--)
{
int r,k;
scanf("%d%d",&r,&k);
que[0]=0;
for(int i=1;i<=k;i++)
{
int x;scanf("%d",&x);
que[++que[0]]=(x-1+ans*type)%n+1;
}
ans=0x3f3f3f3f;
int lca=que[1];
for(int i=2;i<=k;i++)
lca=LCA(lca,que[i]);
for(int i=1;i<=k;i++)
{
int w1=askmax(root[que[i]],root[fa[lca][0]],1,1e9,1,r);
int w2=askmin(root[que[i]],root[fa[lca][0]],1,1e9,r,1e9);
if(w1&&w2)ans=min(ans,min(r-w1,w2-r));
else if(w1)ans=min(ans,r-w1);
else if(w2)ans=min(ans,w2-r);
}
printf("%d\n",ans);
}
return 0;
}

rp++

[CSP-S模拟测试]:e(树上主席树)的更多相关文章

  1. [CSP-S模拟测试]:序列(主席树)

    题目描述 小$A$把自己之前得到的序列展示给了小$B$,不过这一次,他并不要求小$B$模仿他之前的行为.他给了小$B$一些询问,每个询问都是$l\ r\ x$的形式,要求小$B$数出在序列的第$l$个 ...

  2. SPOJ COT Count on a tree(树上主席树 + LCA 求点第k小)题解

    题意:n个点的树,每个点有权值,问你u~v路径第k小的点的权值是? 思路: 树上主席树就是每个点建一棵权值线段树,具体看JQ博客,LCA用倍增logn求出,具体原理看这里 树上主席树我每个点的存的是点 ...

  3. p3302 [SDOI2013]森林(树上主席树+启发式合并)

    对着题目yy了一天加上看了一中午题解,终于搞明白了我太弱了 连边就是合并线段树,把小的集合合并到大的上,可以保证规模至少增加一半,复杂度可以是\(O(logn)\) 合并的时候暴力dfs修改倍增数组和 ...

  4. 【洛谷2633】Count on a tree(树上主席树)

    点此看题面 大致题意: 给你一棵树,每次问你两点之间第\(k\)小的点权,强制在线. 主席树 这种题目强制在线一般就是数据结构了. 而看到区间第\(k\)小,很容易就能想到主席树. 至少不会有人想到树 ...

  5. Count on a tree 树上主席树

    Count on a tree 树上主席树 给\(n\)个树,每个点有点权,每次询问\(u,v\)路径上第\(k\)小点权,强制在线 求解区间静态第\(k\)小即用主席树. 树上主席树类似于区间上主席 ...

  6. bzoj3123 [Sdoi2013]森林 树上主席树+启发式合并

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3123 题解 如果是静态的查询操作,那么就是直接树上主席树的板子. 但是我们现在有了一个连接两棵 ...

  7. BZOJ 2588: Spoj 10628. Count on a tree [树上主席树]

    2588: Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MBSubmit: 5217  Solved: 1233 ...

  8. ☆ [洛谷P2633] Count on a tree 「树上主席树」

    题目类型:主席树+\(LCA\) 传送门:>Here< 题意:给出一棵树.每个节点有点权.问某一条路径上排名第\(K\)小的点权是多少 解题思路 类似区间第\(K\)小,但放在了树上. 考 ...

  9. [bzoj3123][洛谷P3302] [SDOI2013]森林(树上主席树+启发式合并)

    传送门 突然发现好像没有那么难……https://blog.csdn.net/stone41123/article/details/78167288 首先有两个操作,一个查询,一个连接 查询的话,直接 ...

随机推荐

  1. sql limit order by and where

    1 sql limit limit size,返回前size行. limit offset , size,返回offset开始的size行,offset从0行开始. 2 sql limit with ...

  2. JavaDoc注释

    标签 说明 JDK 1.1 doclet 标准doclet 标签类型 @author 作者 作者标识 √ √ 包. 类.接口 @version 版本号 版本号 √ √ 包. 类.接口 @param 参 ...

  3. springboot 整合 tobato 的 fastdfs 实现文件上传和下载

    添加项目所需要的依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId ...

  4. Linux 创建与删除(5)

    相对于Windows下的右键新建文件与删除,我更喜爱Linux下的命令式创建与删除,真的方便.不过Windows下也可以借助工具来实现,比如git bash.cmder等等终端工具. 创建文件 新建文 ...

  5. P1754球迷购票问题

    这是一道动态规划题,其实也是个数论题. 有n人拿50,有n人拿100买票,必须让50元的人买,不然无法找零钱,问最多有几种方案可以每一次都买票成功.这个题首先令人想到搜索,但是随即发现dp是正解,于是 ...

  6. hdu 2586 How far away ? ( 离线 LCA , tarjan )

    How far away ? Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)To ...

  7. 剑指offer-对称二叉树-树-python

    题目描述 请实现一个函数,用来判断一颗二叉树是不是对称的.注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的.   # -*- coding:utf-8 -*- # class TreeNo ...

  8. linux中文件权限格式与chmod命令以及用户和用户组的管理

    简单了解一下linux中的文件权限格式与chmod命令 chmod命令:改变文件或者目录的权限 格式:chmod [参数] [<权限范围><符号><权限代码>] - ...

  9. 梯度下降算法(Gradient descent)GD

    1.我们之前已经定义了代价函数J,可以将代价函数J最小化的方法,梯度下降是最常用的算法,它不仅仅用在线性回归上,还被应用在机器学习的众多领域中,在后续的课程中,我们将使用梯度下降算法最小化其他函数,而 ...

  10. MySQL中Innodb的聚簇索引和非聚簇索引

    聚簇索引 数据库表的索引从数据存储方式上可以分为聚簇索引和非聚簇索引(又叫二级索引)两种.Innodb的聚簇索引在同一个B-Tree中保存了索引列和具体的数据,在聚簇索引中,实际的数据保存在叶子页中, ...