标签:cnt 正整数 int 1000001 fa 树上 type CSP 模拟
题目传送门(内部题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++
标签:cnt,正整数,int,1000001,fa,树上,type,CSP,模拟 来源: https://www.cnblogs.com/wzc521/p/11660178.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。