【bzoj4543】Hotel加强版(thr)
Solution
一年前的题== 然而一年前我大概是在划水qwq
其实感觉好像关键是。。设一个好的状态?然后。。你要用一种十分优秀的方式快乐转移qwq
首先是状态,我们设\(f[x][i]\)表示以\(x\)为根的子树中,与\(x\)的距离为\(i\)的节点数量,\(g[x][i]\)表示。。\(x\)子树内形如下图的点对\((a,b)\)(无序)的数量
其中\(d\)是一个。。不确定的值(说白了就是所有的\(d\)都要考虑到),或者更加直白地说,只要在\(x\)节点上“接上”一条长度为\(i\)的边(边连着一个节点\(y\)),那么\(y,a,b\)可以构成一个满足题目要求的方案
然后这个时候我们就可以快乐转移了,枚举\(x\)的后继\(u\):
g[x][i]&+=f[x][i]*f[u][i-1]+g[u][i+1]\\
f[x][i]&+=f[u][i-1]\\
\end{aligned}
\]
其中\(i\)的范围都是\(1\sim\)子树内的最大深度
稍微解释一下\(g\)的转移:前面的乘法的话就是\(lca\)为\(x\)的情况,后面的话就是从子树中直接继承上来(注意\(+1\)的话是因为\(i\)是被减的那个量)
接下来是答案的统计,考虑统计经过\(x\)的方案,我们有:
\]
同样的\(i\)的范围也是\(1\sim\)子树内的最大深度
那么这个时候可能会有疑问,接上去的那个点的连边不能是一个带“折”的边吗,为什么可以直接用不带折的\(f\)算呢?其实稍微画一下图:
(注意图中的一条边。。可能是一条链只是我懒得画了qwq)我们会发现这种情况其实会在统计图中那个没有标号的节点的时候统计到(没有标号的节点的\(g\)中是可能包含了\((a,b)\)这种情况的(如果他们可能构成一种合法方案的话),然后这个时候\(y\)这个节点其实就是\(f\)中的一部分,所以如果可能构成合法方案的话是会被算进空白节点的贡献中的
(所以说其实。。也不能够叫做统计经过\(x\)的方案的答案)
然后现在的问题就是我们怎么快速转移
发现那个\(i\)的变化很有规律,考虑当我们在树形dp中将第一个儿子的值拿来更新父亲的时候的情况,稍微写一下大概是这样:
f[x][i]&=f[u][i-1]\\
g[x][i]&=g[u][i+1]\\
\end{aligned}
\]
我们将\(f[x],g[x],f[u],g[u]\)都看成一个整体的话,\(f[u]\)到\(f[x]\)的转移其实相当于整体向前或向后偏移了一位,\(g[x]\)和\(g[u]\)的转移也是一样,所以我们其实可以用指针(或者。。下标偏移一下什么的,我的代码写的就是这个因为我不太会用指针qwq)来实现\(O(1)\)的转移
然后对于后面的情况我们都要老老实实枚举\(i\),因此转移复杂度是跟\(u\)的子树最大深度相关的
所以我们不妨考虑把子树最大深度最大的那个后继钦定为第一个后继,\(O(1)\)转移它的信息,然后其他的后继就\(O(dep)\)转移(其实就是长链剖分一下qwq把重儿子摆在一起),这样的话就能够做到整体复杂度\(O(n)\)了(证明的话我不是很会qwq网上看到dalao的博客中说的貌似是直接用深度相减算出一个点的转移的复杂度然后求一下和发现除了叶子节点以外的所有点的\(dep\)都被抵消了所以就是\(O(n)\)了)
然后再稍微说一下下标偏移写法的实现:具体一点就是我们考虑将所有的\(f\)的值排成一排(\(g\)的值也是一样),像树链剖分中的线段树一样将一条长链中所有的节点的信息放在连续的一段,链上的转移的话\(f\)相当于每次往后移一位,\(g\)相当于每次往前移一位(因此在存的时候一条链预留的长度应该\(*2\),因为要预留往前移的空间)
转移的时候一定要注意边界。。。
代码大概长这个样子
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int N=5*(1e5)+10;
struct xxx{
int y,nxt;
}a[N*2];
int h[N],dep[N],top[N],mx[N],son[N],pre[N],pos[N];
int dfn[N];
ll f[N*10],g[N*10];
int n,m,tot,dfn_t,lis_pos;
ll ans;
void add(int x,int y){a[++tot].y=y; a[tot].nxt=h[x]; h[x]=tot;}
void dfs(int fa,int x,int d){
int u;
dep[x]=d; mx[x]=1;
pre[x]=fa; son[x]=0;
for (int i=h[x];i!=-1;i=a[i].nxt){
u=a[i].y;
if (u==fa) continue;
dfs(x,u,d+1);
mx[x]=max(mx[x],mx[u]+1);
if (mx[son[x]]<mx[u]+1) son[x]=u;
}
}
void dfs1(int fa,int x){
int u;
dfn[x]=++dfn_t;
if (son[x]){
top[son[x]]=top[x];
dfs1(x,son[x]);
}
for (int i=h[x];i!=-1;i=a[i].nxt){
u=a[i].y;
if (u==fa||u==son[x]) continue;
top[u]=u; pos[u]=lis_pos+mx[u];
lis_pos+=mx[u]*2;
dfs1(x,u);
}
}
int locf(int x,int i){return dfn[x]+i;}
int locg(int x,int i){return pos[top[x]]-(dep[x]-dep[top[x]])+i;}
int calc(int x,int u){
for (int i=1;i<=mx[u];++i)
ans+=f[locf(u,i-1)]*g[locg(x,i)];
for (int i=1;i<mx[u];++i)
ans+=g[locg(u,i)]*f[locf(x,i-1)];
for (int i=0;i<mx[u]-1;++i)
g[locg(x,i)]+=g[locg(u,i+1)];
for (int i=1;i<=mx[u];++i){
g[locg(x,i)]+=f[locf(x,i)]*f[locf(u,i-1)];
f[locf(x,i)]+=f[locf(u,i-1)];
}
}
void solve(int fa,int x){
int u;
if (!son[x]){
f[locf(x,0)]=1; g[locg(x,0)]=0;
return;
}
solve(x,son[x]);
g[locg(x,mx[x])]=g[locg(x,mx[x]-1)]=0;
ans+=g[locg(x,0)];
f[locf(x,0)]=1;
for (int i=h[x];i!=-1;i=a[i].nxt){
u=a[i].y;
if (u==fa||u==son[x]) continue;
solve(x,u);
calc(x,u);
}
}
void init(){
memset(h,-1,sizeof(h));
tot=0;
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
}
int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
int x,y;
while (1){
scanf("%d",&n);
if (!n) return 0;
init();
for (int i=1;i<n;++i){
scanf("%d%d",&x,&y);
add(x,y); add(y,x);
}
dfs(0,1,1);
dfn_t=0; lis_pos=0;
top[1]=1; pos[1]=lis_pos+mx[1];
lis_pos=mx[1]*2;
dfs1(0,1);
ans=0;
solve(0,1);
printf("%lld\n",ans);
}
}
【bzoj4543】Hotel加强版(thr)的更多相关文章
- BZOJ4543 Hotel加强版
题面 $\text{BZOJ}$间接权限题 洛谷的弱化版 题解 三点距离两两相等要满足以下条件: 有一个相同的$\text{LCA}$ 所以如果存在一个点,使得另外两个点在它子树中,距离为$d$,且$ ...
- BZOJ4543 Hotel加强版(长链剖分)
题意 求一棵树上,两两距离相等的三个点的三元组(无序)的个数. 题解 转自 CaptainHarryChen 的博客 CODE 代码中的f,gf,gf,g对应题解中的num,waynum,waynum ...
- 【BZOJ4543】Hotel加强版(长链剖分)
[BZOJ4543]Hotel加强版(长链剖分) 题面 BZOJ,没有题面 洛谷,只是普通版本 题解 原来我们的\(O(n^2)\)做法是设\(f[i][j]\)表示以\(i\)为根的子树中,距离\( ...
- 【BZOJ4543】Hotel加强版
[BZOJ4543]Hotel加强版 题面 bzoj 洛谷 $ps:$在洛谷看题在bzoj交... 题解 我们分析一下这个问题,要怎么样的点才满足三点距离两两相等呢? 1.存在三个点有共同的$LCA$ ...
- BZOJ4543 POI2014 Hotel加强版 【长链剖分】【DP】*
BZOJ4543 POI2014 Hotel加强版 Description 同OJ3522 数据范围:n<=100000 Sample Input 7 1 2 5 7 2 5 2 3 5 6 4 ...
- BZOJ4543 [POI2014]Hotel加强版
题意 有一个树形结构,每条边的长度相同,任意两个节点可以相互到达.选3个点.两两距离相等.有多少种方案? 数据范围:n<=100000 分析 参照小蒟蒻yyb的博客. 我们先考虑一个\(O(n^ ...
- 【BZOJ4543】[POI2014]Hotel加强版 长链剖分+DP
[BZOJ4543][POI2014]Hotel加强版 Description 同OJ3522数据范围:n<=100000 Sample Input 7 1 2 5 7 2 5 2 3 5 6 ...
- 4543: [POI2014]Hotel加强版
4543: [POI2014]Hotel加强版 链接 分析: f[u][i]表示子树u内,距离u为i的点的个数,g[u][i]表示在子树u内,已经选了两个深度一样的点,还需要在距离u为i的一个点作为第 ...
- 蒟蒻的长链剖分学习笔记(例题:HOTEL加强版、重建计划)
长链剖分学习笔记 说到树的链剖,大多数人都会首先想到重链剖分.的确,目前重链剖分在OI中有更加多样化的应用,但它大多时候是替代不了长链剖分的. 重链剖分是把size最大的儿子当成重儿子,顾名思义长链剖 ...
随机推荐
- HTTP 两种基本请求方法 GET和 POST的区别
GET方法 1.GET交互方式是从服务器上获取数据,而并非修改数据,所以GET交互方式是安全的.就像数据库查询一样,从数据库查询数据,并不会影响数据库的数据信息,对数据库来说,也就是安全的.2.GET ...
- Mybatis-Plus的填坑之路 - Lynwood/wunian7yulian
目录 Mybatis-Plus 我来填坑~ 目录 一.简单介绍 官方说明 : 成绩: 最新版本: 开发层面MyBatis-Plus特色 Mybatis-Plus中的Plus 二.MP的特性 三.MP框 ...
- SQL语句--连接查询
一.连接查询有以下几种 1.内连接查询 select * from t1 inner join t2 on t1.x = t2.x; 返回有关联的行 2.外链接查询 以下写法都省略了 中间的 out ...
- 多重共性和VIF检验
图片来源https://wenku.baidu.com/view/7008df8383d049649b66581a.html 和 https://wenku.baidu.com/view/6acdf9 ...
- R之RMySQL
linux,mysql和R的版本信息: Linux naci 3.19.0-16-generic #16-Ubuntu SMP Server version: 5.6.24-0ubuntu2 (Ubu ...
- 算法笔记(c++)--使用一个辅助栈排列另一个栈
算法笔记(c++)--使用一个辅助栈排列另一个栈 仅仅使用一个辅助栈,不使用其他数据结构来排列一个栈,要求,上大下小. 分析下.肯定是先吧主栈中的数据都放到辅助栈中,在辅助栈中上小下大. 1.首先循环 ...
- tendermint 跟tikv结合
import ( "fmt" "github.com/allegro/bigcache" "github.com/kooksee/usmint/cmn ...
- Hibernate查询的六种方式
Hibernate查询的六种方式 分别是HQL查询,对象化查询Criteria方法,动态查询DetachedCriteria,例子查询,sql查询,命名查询. 如果单纯的使用hibernate ...
- Intense Heat(前缀和或尺取)
The heat during the last few days has been really intense. Scientists from all over the Berland stud ...
- oracle数据库 expdp/impdp 和 exp/imp
--EXPDP导出,需要系统用户权限,一般不使用--sqlplus--1.创建dmp导出逻辑目录 create directory 目录名 as '目录路径' create directory exp ...