2021牛客暑期多校训练营9,签到题HE
Posted 小哈里
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021牛客暑期多校训练营9,签到题HE相关的知识,希望对你有一定的参考价值。
题号 标题 已通过代码 通过率 团队的状态
A A Math Challenge 点击查看 34/412 未通过
B Best Subgraph 点击查看 10/77 未通过
C Cells 点击查看 100/283 未通过
D Divide-and-conquer on Tree 点击查看 8/95 未通过
E Eyjafjalla 点击查看 652/3232 未通过(倍增,dfs序,主席树)
F Financial Order Execution 点击查看 2/125 未通过
G Glass Balls 点击查看 65/135 未通过
H Happy Number 点击查看 1489/2496 通过(签到)
I Incentive Model 点击查看 197/546 未通过
J Jam 点击查看 94/1106 未通过
H Happy Number
题意:
- 一个数字是快乐的当且仅当其在10进制下只由236组成,求第n个快乐数,n<1e9。
思路:
- 首先容易想到3进制,但是直接进制转换不能通过,找了一下规律发现,
0-2,1-3,2-6,00-22,01-23,02-26,10-32,11-32,12-33,,000102在三进制里明显是不合法的,因为和012重复了,但是快乐数里确实合法的。所以在进制转换的时候稍微改一下。
#include<bits/stdc++.h>
using namespace std;
string p="236";
int main(){
int n; cin>>n;
string s="";
while(n>0){
n--;
s = p[n%3]+s;
n /= 3;
}
cout<<s;
return 0;
}
E Eyjafjalla
题意:
- 题意:给定一个以1为根的有根树,孩子的点权小于父亲的点权。 多次询问,每次询问包含x节点的权值范围为[l, r] 的极大连通块的大小。
思路:
- 病毒传播可以看作两个阶段,第一个阶段先上升到最高的一个节点p(p的温度大于r),第二阶段感染p的子树中所有温度大于l的城市。
- 第一阶段可以通过倍增法求得p
- 第二阶段相当于在p的子树中查询权值大于l的节点个数,根据每个节点的dfs序建立可持久化线段树, 然后在线段树上查询即可。时间复杂度O(n log n)。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5+10;
int n;
vector<int>G[maxn];
int a[maxn];
//倍增找p
int fa[maxn], up[maxn][30];
void getf(){
for(int i = 1; i <= n; i++)up[i][0]=fa[i];
for(int j = 1; j <= 20; j++)
for(int i = 1; i <= n; i++)
up[i][j] = up[up[i][j-1]][j-1];//i向上2^j层的祖先
}
//预处理dfs序[dfn,low]
int clk, dfn[maxn], low[maxn], ord[maxn];
void pre(int x, int f){
fa[x] = f;
dfn[x] = ++clk;
ord[clk] = x;
for(int to: G[x]){
if(to != f)pre(to,x);
}
low[x] = clk;
}
//主席树
int tot, rt[maxn<<5], lch[maxn<<5], rch[maxn<<5], sum[maxn<<5];
void modify(int x, int f, int l, int r, int pos){ //v[pos]+=1;
if(l==r){
sum[x] = sum[f]+1;
return ;
}
int mid = l+r>>1;
if(pos <= mid){
rch[x] = rch[f];//直接用上一棵树的节点
lch[x] = ++tot; //需要新建节点
modify(lch[x], lch[f], l, mid, pos);
}else{
lch[x] = lch[f];
rch[x] = ++tot;
modify(rch[x], rch[f], mid+1,r,pos);
}
sum[x] = sum[lch[x]]+sum[rch[x]];
}
int query(int p, int l, int r, int ll, int rr){//查询版本线段树值域范围在[l,r]的节点个数
if(p==0)return 0;
if(ll<=l && r<=rr)return sum[p];
if(l>rr || r<ll)return 0;
int mid = (l+r)>>1, ans = 0;
ans += query(lch[p], l, mid, ll, rr);
ans += query(rch[p], mid+1, r, ll, rr);
return ans;
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n;
for(int i = 1; i < n; i++){
int u, v; cin>>u>>v;
G[u].push_back(v);
G[v].push_back(u);
}
for(int i = 1; i <= n; i++)cin>>a[i]; a[0] = 1e9+7;
pre(1,0);
getf();
for(int i = 1; i <= n; i++){//建立n个版本的值域线段树
rt[i] = ++tot;
modify(rt[i], rt[i-1], 1, 1e9, a[ord[i]]);
}
int q; cin>>q;
while(q--){
int x, l, r; cin>>x>>l>>r;
if(a[x]<l || a[x]>r){ cout<<"0\\n"; continue; }
for(int i = 20; i >= 0; i--){//先上升到最高点,满足刚好a[x]>r
if(a[up[x][i]]<=r)x=up[x][i];
}
//查询子树[dfn[x]-1, low[x]]中,权值在[l,r]中的节点个数
cout<<query(rt[low[x]], 1, 1e9, l,r)-query(rt[dfn[x]-1], 1,1e9, l, r)<<"\\n";
}
return 0;
}
以上是关于2021牛客暑期多校训练营9,签到题HE的主要内容,如果未能解决你的问题,请参考以下文章