牛客小白月赛12 H(dfs序+线段树),F(分块思想+bit),J(二分)
H 华华和月月种树
链接:https://ac.nowcoder.com/acm/contest/392/H
思路:先得到整棵树最终的形态,在这棵树上进行三种操作,用dfs跑下,第二种操作就直接对最终形态树上这个点子树区间操作,第一种操作的时候是新加一个点,此时我们将那个点的权值设为0就好了,最后单点查询。。,很简单的数据结构题。
实现代码:
#include<bits/stdc++.h> using namespace std; const int M = 4e5+10; #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 #define mid int m = (l + r) >> 1 vector<int>g[M]; int sum[M<<2],lazy[M<<2],a[M],b[M],cnt,head[M],in[M],out[M]; int tot,op[M]; void dfs(int u,int fa){ in[u] = ++tot; for(int i = 0;i < g[u].size();i++){ int v = g[u][i]; if(v != fa) dfs(v,u); } out[u] = tot; } void pushdown(int l,int r,int rt){ if(lazy[rt]){ mid; lazy[rt<<1] += lazy[rt]; lazy[rt<<1|1] += lazy[rt]; sum[rt<<1] += lazy[rt]*(m-l+1); sum[rt<<1|1] += lazy[rt]*(r-m); lazy[rt] = 0; } } void update(int L,int R,int c,int l,int r,int rt){ if(L <= l&&R >= r){ sum[rt] += (r-l+1)*c; lazy[rt] += c; return ; } pushdown(l,r,rt); mid; if(L <= m) update(L,R,c,lson); if(R > m) update(L,R,c,rson); } void update1(int p,int c,int l,int r,int rt){ if(l == r){ sum[rt] = 0; return; } pushdown(l,r,rt); mid; if(p <= m) update1(p,c,lson); else update1(p,c,rson); } int query(int p,int l,int r,int rt){ if(l == r){ return sum[rt]; } pushdown(l,r,rt); mid; if(p <= m) return query(p,lson); else return query(p,rson); } int main() { ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); int n; cin>>n; int cnc = 1; for(int i = 1;i <= n;i ++){ cin>>op[i]>>a[i]; a[i] ++; if(op[i] == 1){ cnc ++; b[i]= cnc; g[a[i]].push_back(cnc); g[cnc].push_back(a[i]); } else if(op[i] == 2) cin>>b[i]; } dfs(1,0); for(int i = 1;i <= n;i ++){ if(op[i] == 2){ update(in[a[i]],out[a[i]],b[i],1,tot,1); } else if(op[i] == 1){ update1(in[b[i]],0,1,tot,1); } else{ cout<<query(in[a[i]],1,tot,1)<<endl; } } return 0; }
F 华华开始学信息学
链接:https://ac.nowcoder.com/acm/contest/392/F
思路: 分块思维+bit, 和去年沈阳网络赛的J一样的思路,只不过那道是在树上的,这道相当于简化版,我们直接将D大小大于400的用bit暴力更新,小于400的用数组标记下就好了
实现代码:
#include<bits/stdc++.h> using namespace std; #define ll long long const int M = 2e5+10; ll c[M],n,vis[M]; vector<ll>v; void add(ll x,ll v){ while(x <= n){ c[x] += v; x += (x&-x); } } ll getsum(ll x){ ll ret = 0; while(x){ ret += c[x]; x -= (x&-x); } return ret; } int main() { ll m,x,op,y; cin>>n>>m; for(ll i = 1;i <= m;i ++){ cin>>op>>x>>y; if(op == 1){ if(x <= 400){ if(!vis[x]) v.push_back(x); vis[x] += y; } else{ for(ll j = x;j <= n;j += x){ add(j,y); } } } else{ ll ans = 0; for(auto &k: v){ ans += (y/k - (x-1)/k)*vis[k]; } ans += getsum(y) - getsum(x-1); cout<<ans<<endl; } } }
J 月月查华华的手机
链接:https://ac.nowcoder.com/acm/contest/392/J
思路:这道题范围给的很大,肯定不能用n*n的复杂度去写,最多只能 n*(logn), 因为子序列的字母之间是有先后关系的,我们先把母序列处理下,把每个字母的位置存到对应的vector里面,判断子序列时候合格时,我们遍历子序列每个字母,在当前字母对应的vector里二分取大于前一个字母位置的数,如果取不到那么这个子序列就不合格,如果取到了就保存下当前位置,继续遍历
实现代码:
#include<bits/stdc++.h> using namespace std; const int M = 1e6+10; vector<int>g[M]; int a[M]; int main() { string s,s1; int n; ios::sync_with_stdio(0); cin.tie(0); cout.tie(0); cin>>s; for(int i = 0;i < s.size();i ++){ a[i] = s[i]-'a'; g[a[i]].push_back(i+1); } cin>>n; for(int i = 1;i <= n;i ++){ cin>>s1; int st = 0,flag = 0; for(int j = 0;j < s1.size();j ++){ int k = s1[j]-'a'; if(g[k].size()==0){ flag = 1;break; } int kk = upper_bound(g[k].begin(),g[k].end(),st) - g[k].begin(); if(kk >= g[k].size()){ flag = 1;break; } st = g[k][kk]; } if(!flag) cout<<"Yes"<<endl; else cout<<"No"<<endl; } }