这玩意好难啊Orz

完全不理解那个模拟深搜到底是什么鬼

果然像我这样的人最好早点滚粗 

要简历虚树 首先要选出虚树里面的点 那么关键点和关键点的LCA都要加入到虚树中来 那我们就深搜一遍 处理出每个节点的dfn值和儿子数

按照dfn值依次枚举每一个关键节点 这样可以把同一棵子树内的节点一起找到

用一个深度单调的栈来维护树中的节点 每次取出一个关键点 求出它和栈顶元素的lca

如果他们的lca的深度小于栈顶元素 lca的深度比栈中第二个元素大 即当前的lca卡在了两个树中的点之间 那么就由lca向当前的栈顶元素连边 无论是否连边 都直接把栈顶元素弹出

如果你当前这次没有连边 说明你没有卡在栈顶两个元素之间 那么他们在之前就已经练好一条边了 可以直接pop掉

当栈顶元素的深度已经比lca小 那么就由栈顶元素向lca连边

这样就完成建立虚树的操作

然后就是DP了

我们首先用两边for循环处理掉虚树上某条边 两个端点的元素会走到同一个端点 即x 走向fa[x] 或者 fa[x] 走向 x

然后我们枚举剩余的节点 它与父亲的边上的点不会都走向同一个点 那么我们求出他们距离的中点 中点以下的走向自己 中点以上的就走向父亲

果然还是好难啊QAQ

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<queue>
#include<map>
#define SF scanf
#define PF printf
#define mp make_pair
#define fir first
#define sec second
#define bit(x) (1<<(x))
using namespace std;
typedef long long LL;
typedef pair <int, int> pii;
const int MAXN = 300000;
int n;
// Add edges
struct Node {int v, next;
} Edge[MAXN*2+10];
int adj[MAXN+10], ecnt;
void addedge(int u, int v) {Node &e = Edge[ecnt];e.v = v; e.next = adj[u]; adj[u] = ecnt++;
}
// DFS and build the tree
int dfn[MAXN+10], dcnt, f[MAXN+10][30], dep[MAXN+10], sz[MAXN+10];
void dfs(int u) {dfn[u] = ++dcnt;// prepare for LCAfor(int i = 1; bit(i) <= dep[u]; i++) f[u][i] = f[f[u][i-1]][i-1];for(int i = adj[u]; ~i; i = Edge[i].next) {int v = Edge[i].v;if(v == f[u][0]) continue;f[v][0] = u; dep[v] = dep[u]+1;dfs(v);sz[u] += sz[v];}sz[u]++;
}
// Go to another point
int Go(int x, int k) {int del = dep[x] - k;for(int i = 20; i >= 0; i--)if(del & bit(i))x = f[x][i];return x;
}
// find LCA
int LCA(int x, int y) {if(dep[x] < dep[y]) swap(x, y);int del = dep[x] - dep[y];for(int i = 20; i >= 0; i--)if(del & bit(i))x = f[x][i];if(x == y) return x;for(int i = 20; i >= 0; i--)if(f[x][i] != f[y][i])x = f[x][i], y = f[y][i];return f[x][0];
}
// solve the problem
int ask[MAXN+10], tree[MAXN+10], tmp[MAXN+10], tot, ans[MAXN+10];
int sta[MAXN+10], fa[MAXN+10], val[MAXN+10], in[MAXN+10];
pii near[MAXN+10];
bool cmp(int a, int b) { return dfn[a] < dfn[b]; }
void solve() {int m; SF("%d", &m);// Read the key pointsfor(int i = 1; i <= m; i++) {int x; SF("%d", &x);ask[i] = tree[i] = tmp[i] = x;near[x] = mp(0, x); ans[x] = 0;}sort(ask+1, ask+1+m, cmp);int top = 0;tot = m;// find the new tree pointsfor(int i = 1; i <= m; i++) {int cur = ask[i];if(!top) sta[++top] = cur, fa[cur] = 0;else {int lca = LCA(sta[top], cur);fa[cur] = lca;while(top && dep[sta[top]] > dep[lca]) {if(dep[sta[top-1]] <= dep[lca]) fa[sta[top]] = lca;top--;}if(sta[top] != lca) {fa[lca] = sta[top]; tree[++tot] = lca;sta[++top] = lca; near[lca] = mp(bit(30), 0);}sta[++top] = cur;}}sort(tree+1, tree+1+tot, cmp);// DPfor(int i = 1; i <= tot; i++) {int x = tree[i];val[x] = sz[x];if(i > 1) in[x] = dep[x] - dep[fa[x]];}for(int i = tot; i > 1; i--) {int x = tree[i], pre = fa[x];near[pre] = min(near[pre], mp(near[x].fir + in[x], near[x].sec));}for(int i = 2; i <= tot; i++) {int x = tree[i], pre = fa[x];near[x] = min(near[x], mp(near[pre].fir + in[x], near[pre].sec));}for(int i = 1; i <= tot; i++) {int x = tree[i], pre = fa[x], sum = sz[Go(x, dep[pre]+1)] - sz[x];if(pre == 0) ans[near[x].sec] += n-sz[x];else {val[pre] -= sum + sz[x];if(near[x].sec == near[pre].sec) ans[near[x].sec] += sum;else {int dis = (dep[x] - dep[pre] - near[x].fir + near[pre].fir) >> 1;if(dis + near[x].fir == near[pre].fir + dep[x] - dep[pre] - dis && near[pre].sec < near[x].sec) dis--;int p = Go(x, dep[x] - dis);ans[near[x].sec] += sz[p] - sz[x];ans[near[pre].sec] += sum + sz[x] - sz[p];}}}for(int i = 1; i <= tot; i++) ans[near[tree[i]].sec] += val[tree[i]];for(int i = 1; i <= m; i++) PF("%d ", ans[tmp[i]]);puts("");
}
// Main
int main() {memset(adj, -1, sizeof(adj));SF("%d", &n);for(int i = 1; i < n; i++) {int u, v; SF("%d%d", &u, &v);addedge(u, v); addedge(v, u);}dfs(1);int _T; SF("%d", &_T); while(_T--) solve();return 0;
}

[BZOJ3572][Hnoi2014]世界树 虚树+DP相关推荐

  1. bzoj3572 [HNOI2014]世界树 虚树 +乱dp

    这个题有Σ的条件,肯定还是用log结构求询问点相关了 但这个题是点之间的距离关系,所以本来想用中点来代替原来的lca,但中点的个数不满足任何单调性,而且个数也不是n个 所以还是要用lca,所以考虑lc ...

  2. [HNOI2014]世界树 (虚树DP+倍增)

    世界树 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息.持续运转的根本基石 ...

  3. bzoj 3572 [Hnoi2014]世界树——虚树

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3572 关于虚树:https://www.cnblogs.com/zzqsblog/p/556 ...

  4. [bzoj3572][HNOI2014]世界树

    题目描述 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息.持续运转的根本基 ...

  5. 洛谷P2495 [SDOI2011]消耗战(虚树dp)

    P2495 [SDOI2011]消耗战 题目链接 题解: 虚树\(dp\)入门题吧.虚树的核心思想其实就是每次只保留关键点,因为关键点的dfs序的相对大小顺序和原来的树中结点dfs序的相对大小顺序都是 ...

  6. BZOJ3572 [Hnoi2014]世界树 【虚树 + 树形dp】

    题目 世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界.在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息.持续运转的根本基石. ...

  7. bzoj3572世界树 虚树+树型动规

    3572: [Hnoi2014]世界树 Time Limit: 20 Sec   Memory Limit: 512 MB Submit: 1786   Solved: 957 [ Submit][ ...

  8. 「HNOI2014」世界树 虚树

    「HNOI2014」世界树 前置技能:虚树. (本题可以通过以下相似的思想用线段树维护子树信息和倍增找中点完成,代码短很多,但本篇题解不涉及) 题解部分 这种总询问点数不大,但是询问次数多,可以想到用 ...

  9. BZOJ3572: [Hnoi2014]世界树

    题解: 首先建出一颗虚树  对于虚树上的每个节点DP找出离得最近的关键节点的编号和距离 然后考虑一遍dfs 对于每条链上子树 我们倍增找到mid位置 然后mid以下的属于下面节点 mid以上的属于上面 ...

  10. luogu3233 世界树 (虚树)

    反正肯定要建虚树,考虑建完之后怎么做 先随便dp一下算出来距离某点最近的询问点mi[x](因为有的虚树上的点它不是询问点嘛) 那我们对于某条链x到fa[x]上的非虚树上的点(包括他们的非虚树上的孩子) ...

最新文章

  1. 如何利用azMan (Authorization Manager) 实现 role-based的安全验证机制
  2. 计算机联锁站按钮继电器电路,计算机联锁系统与站内各种电路结合说明.DOC
  3. 支付通道接口异常统计上报
  4. c语言野指针和空指针,C++中的空指针和野指针
  5. 学习React的一知半解
  6. Web服務器的配置方法
  7. permgen_打破PermGen神话
  8. 2010数据库SQL Server 盘点
  9. 你发这些什么目的_微信CRM系统究竟是什么?
  10. python的变量在使用之前是否要进行声明_python – 如何在使用之前测试变量是否已初始化?...
  11. mysql高可用性方案(2)
  12. Java static的使用
  13. opencv立方体的画法_opencv几何图形画法
  14. c++中getline()函数用法与坑
  15. 腾讯云服务器+RAKSmart国内外服务器使用记录
  16. HTML5 案例学习笔记
  17. SE-第一章-整理-CCUT-ZY
  18. 矩阵与行列式的区别 行列式简单理解(二三阶)
  19. GARCH-QR非线性回归(GQNR)交易模型(初稿)
  20. 一款MS SQL查询分析工具(1.3M)

热门文章

  1. 苹果App卡审怎么办?
  2. Java 动手写爬虫: 三、爬取队列
  3. 几款远程登录软件的对比
  4. 预制包含很多lib库的apk
  5. iOS8新功能新特性
  6. 在后台管理系统中如何设计账户管理?
  7. PNP NPN 三线制接近开关接线
  8. 跑通CHPDet模型
  9. PHPwebshell2022免杀bypass阿里云盾等所有安全设备
  10. ila、dbg_hub、jatg时钟关系