[BZOJ3572][Hnoi2014]世界树 && 虚树+DP
来源:互联网 发布:mac 设置homekit 编辑:程序博客网 时间:2024/05/18 14:22
这玩意好难啊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 edgesstruct 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 treeint dfn[MAXN+10], dcnt, f[MAXN+10][30], dep[MAXN+10], sz[MAXN+10];void dfs(int u) { dfn[u] = ++dcnt; // prepare for LCA for(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 pointint 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 LCAint 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 problemint 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 points for(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 points for(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);// DP for(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("");}// Mainint 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;}
0 0
- [BZOJ3572][Hnoi2014]世界树 && 虚树+DP
- [ BZOJ3572 ] [ Hnoi2014 ] [ 虚树 ] [ 树形DP ] 世界树
- [BZOJ3572][HNOI2014]世界树-虚树+树形DP
- 【BZOJ3572】【Hnoi2014】世界树 虚树
- [BZOJ3572][Hnoi2014]世界树(虚树+树形dp+二分+lca)
- bzoj3572: [Hnoi2014]世界树
- bzoj3572: [Hnoi2014]世界树
- bzoj3572: [Hnoi2014]世界树
- [BZOJ3572][HNOI2014]世界树
- [BZOJ3572] [Hnoi2014]世界树
- bzoj3572: [Hnoi2014]世界树
- [bzoj3572][HNOI2014]世界树
- 【HNOI2014】bzoj3572 世界树
- BZOJ3572: [Hnoi2014]世界树(虚树)
- bzoj3572 世界树 虚树&树形dp
- 【BZOJ】3572: [Hnoi2014]世界树【虚树DP】
- 3572: [Hnoi2014]世界树 虚树+DP
- bzoj 3572 [Hnoi2014]世界树 虚树 dp
- windows下安装Maven
- PHP自定义函数实现文字到拼音转换功能
- Python exec 和 eval
- Android4.×耳机插拔检测
- 数组中的逆序对
- [BZOJ3572][Hnoi2014]世界树 && 虚树+DP
- Android=判断当前是否处于前台
- Mac OS X 快捷键(完整篇)
- Python中进行中文注释
- Struts 2框架的大致处理流程
- JAVA Pattern和Matcher 的用法
- 阅读书单
- 本地上传图片后立即显示(转载,FileReader用法参见另一篇)
- ubuntu vim中文乱码问题