题目传送门(内部题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. Java第二周总结

    一.Java 基础程序设计 第一章: (1)在Java中源文件的扩展名为.java,编译Java源程序文件产生相应的字节码文件扩展名为.class (2)public class定义要求类名称保持一致 ...

  2. 实用网站推荐——office模板(PPT)

    今天给大家分享一批Office的模板网站! office模板比较多的是PPT模板,做PPT是一件非常痛苦的事,自己做的要么太丑,要么搭配太单一,所以今天给大家分享一批网站,再也不用愁做PPT了. wo ...

  3. 一些重温CSS需要注意的小细节

    <!-- CSS是用于描述页面展示的语言 字体.颜色.大小.间距,将内容分为多列 或者简单的动画及其他的装饰效果 决定了长啥样 html房子的骨架 css负责装修 怎么装修一个房子呢? 首先就是 ...

  4. MySQL8 clone plugin

    安装MySQl8.0.17 下载 MySQL8.0.17 二进制版本 https://dev.mysql.com/downloads/mysql/ 解压,修改权限 -linux-glibc2.-x86 ...

  5. selectnodes和selectSingleNode

    selectnodes: selectNodes和ChildNodes获取XML内容数组的差异性 我们在使用XML进行查询或者变更数据的时候,需要注意两个很相近但结果相差很大的用法,如下: 1: Xm ...

  6. vue组件命名和传值

    一.vue组件命名: 组件有好几种命名方式, 可以使用 component-vue (短横线分隔命名).componentVue  (驼峰式命名) 或ComponentVue  (单词首字母) 因为h ...

  7. centos 7 无网络情况下,解决yum 安装依赖rpm包

    方法一:在一台有网络的机器,用yum下载好所需程序,传到另外一台网络的机器上安装 yum install xtrabackup --downloadonly --downloaddir=/rpmpat ...

  8. linux获取外网ip

    引言:目前获取ip的方法中,ifconfig和ip获取函数得到的都是内网ip.有时候需要获取外网ip,目前通用的做法,是向外部服务器发送请求,解析外部服务器响应,从而得到的自己的外网ip.linux下 ...

  9. 利用AXI VDMA实现OV5640摄像头采集

    利用AXI VDMA实现OV5640摄像头采集 导读:摄像头采样图像数据后经过VDMA进入DDR,通过PS部分控制,经过三级缓存,将DDR中保持的图形数据通过VDMA发送出去.在FPGA的接收端口产生 ...

  10. 简洁的Asp.net菜单控件

    http://www.cnblogs.com/ruinet/archive/2009/11/10/1599984.html asp.net自带的菜单控件采用的table和javascript,导致生成 ...