2021牛客暑期多校训练营9 E

好题-题面🎈#

翻译翻译就是root为1的n个点的树,root点值最高,离root越远点值越小,现在m个询问,问从pos点出发,点值在【l,r】区间的点,最多能覆盖多少点

Copy
输入 4 1 2 1 3 2 4 10 8 7 6 3 1 10 10 2 6 7 3 7 10 输出 1 //只有1点 0 //2点值8,不符合6~7 3 //1 2 3点

思路🎈#

以主城为根。离主城越远温度越低。首先可以根据病毒的温度区间[l,r]

可以找到病毒可以传播到离主城最近的城市是哪个。这个用倍增很好做。

找到这个点之后就是统计这个点为根的子树有多少温度在r以上。

dfs序做主席树,然后二分找比k值大于等于的个数

(比赛自己写的主席树写开花了,于是抄了个板子)

划分树ac代码#

Copy
#include <bits/stdc++.h> #include<complex> #define ull unsigned long long #define ll long long #define mem(a,b) memset(a,b,sizeof(a)) using namespace std; const int N=1e5+10; struct Edge { int v, nxt; } E[N*2]; int Head[N], erear; void edge_init() { erear = 0; memset(Head, -1, sizeof(Head)); } void edge_add(int u, int v) { E[erear].v = v; E[erear].nxt = Head[u]; Head[u] = erear++; } int sorted[N*2],dfn=0,zz[N]; int L[N],R[N]; int fa[N][20]; void DFS(int u, int f) { sorted[++dfn]=zz[u]; L[u]=dfn; for(int i = Head[u]; ~i; i = E[i].nxt) { int v = E[i].v; if(v == f) continue; DFS(v, u); fa[v][0]=u; } sorted[++dfn]=zz[u]; R[u]=dfn; } const int INF = 1e9; const int MAXN = 2e5 + 5; const int LOG_N = 30; // tree[dep][i] 第dep层第i个位置的数值 int tree[LOG_N][MAXN]; // toleft[p][i] 第p层前i个数中有多少个整数分入下一层 int toleft[LOG_N][MAXN]; void build(int l, int r, int dep) { if(l == r) return; int mid = (l + r) / 2; int same = mid - l + 1; // 和中点数相同的数的个数 for(int i = l; i <= r; i++) if(tree[dep][i] < sorted[mid]) same--; int lpos = l, rpos = mid + 1; for(int i = l; i <= r; i++) { if(tree[dep][i] < sorted[mid]) tree[dep + 1][lpos++] = tree[dep][i]; else if(tree[dep][i] == sorted[mid] && same) { tree[dep + 1][lpos++] = tree[dep][i]; same--; } else tree[dep + 1][rpos++] = tree[dep][i]; toleft[dep][i] = toleft[dep][l - 1] + lpos - l; } build(l, mid, dep + 1); build(mid + 1, r, dep + 1); } // [L,R]里查询子区间[l,r]第k小的数 int query(int L1, int R1, int l, int r, int dep, int k) { if(l == r) return tree[dep][l]; int mid = L1 + R1>>1; // 有多少个查询区间内的节点会进入下一层的左子树 int cnt = toleft[dep][r] - toleft[dep][l - 1]; if(cnt >= k){ int newl = L1 + toleft[dep][l - 1] - toleft[dep][L1 - 1]; int newr = newl + cnt - 1; return query(L1, mid, newl, newr, dep + 1, k); } else{ int newr = r + toleft[dep][R1] - toleft[dep][r]; int newl = newr - (r - l - cnt); return query(mid + 1, R1, newl, newr, dep + 1, k - cnt); } } int solve(int s, int t, int h) { int l = 1, r = (t - s) + 1, mid; int ans = 0; while(l <= r) { mid = (l + r) / 2; if(query(1, dfn, s, t, 0, mid) <= h) { ans = mid; l = mid + 1; } else r = mid - 1; } return ans; } int n; int main(){ edge_init(); scanf("%d",&n); for(int i=1;i<n;i++){ int u,v;scanf("%d%d",&u,&v); edge_add(u,v); edge_add(v,u); } for(int i=1;i<=n;i++){ scanf("%d",&zz[i]); } DFS(1,0); for(int i=1;i<=dfn;i++){ tree[0][i]=sorted[i]; } sort(sorted+1,sorted+1+dfn); build(1,dfn,0); for (int i=1;i<20;i++){ for (int j=1;j<= n;j++){ fa[j][i] = fa[fa[j][i - 1]][i - 1]; } } int m;scanf("%d",&m); while(m--){ int u,mx,mi; scanf("%d%d%d",&u,&mi,&mx); if(zz[u]>mx || zz[u]<mi){ printf("0\n");continue; } int p=19; while (p--){ if (fa[u][p] == 0 || zz[fa[u][p]]>mx) continue; u=fa[u][p]; } mi--;//这里是找小于mi的个数 int l=L[u],r=R[u]; int zhi=solve(l,r,mi); zhi=r-l+1-zhi; printf("%d\n",zhi/2); } return 0; } /* 4 1 2 1 3 2 4 10 8 7 6 3 1 10 10 2 6 7 3 7 10 */

水哥的主席树orz#

Copy
#pragma warning(suppress : 4996) #define _CRT_SECURE_NO_WARNINGS #include <list> #include <iostream> #include <map> #include <fstream> #include <algorithm> using namespace std; typedef long long ll; const int N = 1e5 + 5; const ll mod = 1e9 + 7; int n; int g[N], edge[N * 2], nex[N * 2]; int lz = 1; int fa[N][18];//倍增 int t[N];//温度 int tmp[N * 3 + 5]; int cid[N], tl[N], tr[N]; int R = 0; int rt[N * 40], ls[N * 40], rs[N * 40], cnt[N * 40], tot; void build(int& p, int l, int r) { p = ++tot; cnt[p] = 0; if (l == r)return; int mid = (l + r) / 2; build(ls[p], l, mid); build(rs[p], mid + 1, r); } void update(int& p, int l, int r, int last, int x) { p = ++tot; int mid = (l + r) >> 1; cnt[p] = cnt[last] + 1; //printf("%d %d\n",p,cnt[p]); ls[p] = ls[last]; rs[p] = rs[last]; if (l == r)return; if (x <= mid) update(ls[p], l, mid, ls[last], x); else update(rs[p], mid + 1, r, rs[last], x); } int query(int x, int y, int l, int r, int h) { if (l == r)return h <= l ? cnt[y] - cnt[x] : 0; int mid = (l + r) >> 1; if (mid + 1 < h) { return query(rs[x], rs[y], mid + 1, r, h); } else if (mid + 1 == h) { return cnt[rs[y]] - cnt[rs[x]]; } else { return cnt[rs[y]] - cnt[rs[x]] + query(ls[x], ls[y], l, mid, h); } } void addEdge(int u, int v) { edge[lz] = v; nex[lz] = g[u]; g[u] = lz++; edge[lz] = u; nex[lz] = g[v]; g[v] = lz++; } int dfsL[N], dfsR[N], dfstot; void dfs(int u, int p) { dfsL[u] = ++dfstot; update(rt[dfsL[u]], 0, R, rt[dfsL[u] - 1], t[u]); for (int i = g[u]; i != 0; i = nex[i]) { int v = edge[i]; if (v == p)continue; dfs(v, u); fa[v][0] = u; } dfsR[u] = dfstot; } int main() { int u, v; int q; scanf("%d", &n); for (int i = 1; i < n; ++i) { scanf("%d%d", &u, &v); addEdge(u, v); } for (int i = 1; i <= n; i++) { scanf("%d", &t[i]); tmp[R++] = t[i]; } scanf("%d", &q); for (int i = 0; i < q; ++i) { scanf("%d%d%d", &cid[i], &tl[i], &tr[i]); tmp[R++] = tl[i]; tmp[R++] = tr[i]; } sort(tmp, tmp + R); R = unique(tmp, tmp + R) - tmp; for (int i = 1; i <= n; ++i) { t[i] = lower_bound(tmp, tmp + R, t[i]) - tmp; } for (int i = 0; i < q; ++i) { tl[i] = lower_bound(tmp, tmp + R, tl[i]) - tmp; tr[i] = lower_bound(tmp, tmp + R, tr[i]) - tmp; } build(rt[0], 0, R); dfs(1, 0); for (int i = 1; i < 18; ++i) { for (int j = 1; j <= n; j++) { fa[j][i] = fa[fa[j][i - 1]][i - 1]; } } for (int i = 0; i < q; ++i) { int u = cid[i]; if (tl[i] > t[u] || tr[i] < t[u]) { printf("0\n"); continue; } int p = 18; while (p--) { if (fa[u][p] == 0 || t[fa[u][p]] > tr[i])continue; u = fa[u][p]; } printf("%d\n", query(rt[dfsL[u] - 1], rt[dfsR[u]], 0, R, tl[i])); } return 0; }

水哥两年不打,都比我这半退役的强啊

去年省赛E题#

是一个求区间前k大之和,有一篇博客

主席树学习

posted @   ouluy  阅读(61)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示
CONTENTS