luogu P3565 [POI2014]HOT-Hotels
无脑暴力+O2=AC
题目要统计距离两两相等的三个点的组数,这三个点之间显然有一个点,并且这三个点到这个点的距离都相同.所以枚举中间这个点作为根,然后bfs整棵树,对于每一层,把以根的某个儿子的子树中在这一层点的数量统计出来,那么这样三元组的数量就是在这些点里面选3个点,并且分别来自不同子树的方案,\(f_{i,0/1/2/3}\)即可
详见代码
// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define LL long long
#define il inline
#define re register
using namespace std;
const int N=5000+10;
il int rd()
{
int x=0,w=1;char ch=0;
while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
LL ans,f[N][4];
int to[N<<1],nt[N<<1],hd[N],dg[N],tot=1,a[N];
bool v[N];
il void add(int x,int y)
{
++tot,to[tot]=y,nt[tot]=hd[x],hd[x]=tot,++dg[x];
++tot,to[tot]=x,nt[tot]=hd[y],hd[y]=tot,++dg[y];
}
int n,m;
int main()
{
n=rd();
for(int i=1;i<n;++i) add(rd(),rd());
for(int i=0;i<=n;++i) f[i][0]=1;
queue<int> id[2],q[2];
for(int i=1;i<=n;++i)
{
memset(v,0,sizeof(v));
v[i]=1;
while(!id[0].empty()) id[0].pop();
while(!id[1].empty()) id[1].pop();
while(!q[0].empty()) q[0].pop();
while(!q[1].empty()) q[1].pop();
m=dg[i];
int nw=1,la=0;
for(int j=hd[i],k=1;j;j=nt[j],++k) id[0].push(k),q[0].push(to[j]);
while(!q[la].empty())
{
memset(a,0,4*(m+1));
while(!q[la].empty())
{
int k=id[la].front(),x=q[la].front();
id[la].pop(),q[la].pop();
++a[k],v[x]=true;
for(int j=hd[x];j;j=nt[j])
{
int y=to[j];
if(!v[y]) id[nw].push(k),q[nw].push(y);
}
}
for(int j=1;j<=m;++j)
{
for(int k=1;k<=3;++k) f[j][k]=f[j-1][k]+f[j-1][k-1]*a[j];
}
ans+=f[m][3];
swap(nw,la);
}
}
printf("%lld\n",ans);
return 0;
}
正解是长链剖分
咕咕咕
其实上面那个dp比较沙雕,可以直接设\(f_{i,j}\)为点\(i\)子树内到\(i\)距离为\(j\)的点个数,\(g_{i,j}\)为点\(i\)子树内,到lca距离为\(d\),且这个lca到\(i\)距离为\(d-j\)的点对个数,然后转移就是
\]
对整棵树长链剖分之后,那么转移时就直接可以继承重儿子的信息,轻儿子直接暴力合并,因为每个点只会在链顶被暴力合并上去,所以复杂度是\(O(n)\)的
#include<bits/stdc++.h>
#define LL long long
#define il inline
#define re register
using namespace std;
const int N=100000+10;
il int rd()
{
int x=0,w=1;char ch=0;
while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
return x*w;
}
int to[N<<1],nt[N<<1],hd[N],tot=1;
il void add(int x,int y)
{
++tot,to[tot]=y,nt[tot]=hd[x],hd[x]=tot;
++tot,to[tot]=x,nt[tot]=hd[y],hd[y]=tot;
}
int n,m;
int ff[N],de[N],dpt[N],son[N];
LL *f[N],*g[N],rbq[N<<3],*uc=rbq,ans;
void dfs1(int x)
{
dpt[x]=de[x];
for(int i=hd[x];i;i=nt[i])
{
int y=to[i];
if(y==ff[x]) continue;
ff[y]=x,de[y]=de[x]+1,dfs1(y),dpt[x]=max(dpt[x],dpt[y]);
if(dpt[son[x]]<dpt[y]) son[x]=y;
}
}
void dd(int x)
{
if(son[x]) f[son[x]]=f[x]+1,g[son[x]]=g[x]-1,dd(son[x]);
f[x][0]=1,ans+=g[x][0];
for(int i=hd[x];i;i=nt[i])
{
int y=to[i];
if(y==ff[x]||y==son[x]) continue;
f[y]=uc,uc+=(dpt[y]-de[x]+1)<<1,g[y]=uc,uc+=(dpt[y]-de[x]+1)<<1;
dd(y);
for(int j=0;j<dpt[y]-de[x];++j)
{
if(j) ans+=f[x][j-1]*g[y][j];
ans+=g[x][j+1]*f[y][j];
}
for(int j=0;j<dpt[y]-de[x];++j)
{
g[x][j+1]+=f[x][j+1]*f[y][j];
if(j) g[x][j-1]+=g[y][j];
f[x][j+1]+=f[y][j];
}
}
}
int main()
{
n=rd();
for(int i=1;i<n;++i) add(rd(),rd());
de[1]=1,dfs1(1);
f[1]=uc,uc+=(dpt[1]+1)<<1,g[1]=uc,uc+=(dpt[1]+1)<<1;
dd(1);
printf("%lld\n",ans);
return 0;
}
luogu P3565 [POI2014]HOT-Hotels的更多相关文章
- Luogu P3577 [POI2014]TUR-Tourism
Luogu P3577 [POI2014]TUR-Tourism 题目链接 题目大意:给出一张\(n\)个点,\(m\)条边的无向图,保证任意两点之间没有点数超过\(10\)的简单路径.选择第\(i\ ...
- luogu P3567 [POI2014]KUR-Couriers
二次联通门 : luogu P3567 [POI2014]KUR-Couriers MMP 指针 RE + MLE + WA..... 不得已...向黑恶的数组实力低头 /* 指针 */ #inclu ...
- 主席树||可持久化线段树||BZOJ 3524: [Poi2014]Couriers||BZOJ 2223: [Coci 2009]PATULJCI||Luogu P3567 [POI2014]KUR-Couriers
题目:[POI2014]KUR-Couriers 题解: 要求出现次数大于(R-L+1)/2的数,这样的数最多只有一个.我们对序列做主席树,每个节点记录出现的次数和(sum).(这里忽略版本差值问题) ...
- P3565 [POI2014]HOT-Hotels
题目描述 There are nn towns in Byteotia, connected with only n-1n−1 roads. Each road directly links two ...
- [luogu]P3572 [POI2014]PTA-Little Bird(单调队列)
P3572 [POI2014]PTA-Little Bird 题目描述 In the Byteotian Line Forest there are nn trees in a row. On top ...
- luogu P3576 [POI2014]MRO-Ant colony
传送门 一群蚂蚁能被吃,也就是走到指定边的两端点之一要走到另一端点时有\(k\)只,我们可以从这两端点逆推,记两个值为走到某个点时最后会被吃掉\(k\)只蚂蚁的蚂蚁数量范围,式子下面有,很好理解(雾) ...
- Luogu P3579 [POI2014]PAN-Solar Panels
题目大意: 给出T组询问,每组询问给出四个数a,b,c,d,每次询问满足a<=x<=b,c<=y<=d的gcd(x,y)的最大值 首先可以想到如果存在gcd(x,y)=k,那么 ...
- luogu P3572 [POI2014]PTA-Little Bird |单调队列
从1开始,跳到比当前矮的不消耗体力,否则消耗一点体力,每次询问有一个步伐限制,求每次最少耗费多少体力 #include<cstdio> #include<cstring> #i ...
- luogu P3572 [POI2014]PTA-Little Bird
题目描述 从1开始,跳到比当前矮的不消耗体力,否则消耗一点体力,每次询问有一个步伐限制,求每次最少耗费多少体力 单调队列优化动态规划 #include<cstdio> #include&l ...
随机推荐
- jdbc,mybatis,hibernate各自有优缺点以及区别
JDBC: 我们平时使用jdbc进行编程,大致需要下面几个步骤: 1,使用jdbc编程需要连接数据库,注册驱动和数据库信息 2,操作Connection,打开Statement对象 3,通过State ...
- Borg Maze POJ - 3026 (BFS + 最小生成树)
题意: 求把S和所有的A连贯起来所用的线的最短长度... 这道题..不看discuss我能wa一辈子... 输入有坑... 然后,,,也没什么了...还有注意 一次bfs是可以求当前点到所有点最短距离 ...
- Leetcode 326.3的幂 By Python
给定一个整数,写一个函数来判断它是否是 3 的幂次方. 示例 1: 输入: 27 输出: true 示例 2: 输入: 0 输出: false 示例 3: 输入: 9 输出: true 示例 4: 输 ...
- MQTT——取消订阅报文和断开连接报文
笔者已经把连接报文,订阅报文,发布报文都讲解了完了.而接下来就是取消订阅报文和断开连接报文.和其他的报文比较的话,他们显示非常简单.甚至笔者觉得可以不必要拿出来讲.只要看一下MQTT文档就没有什么不清 ...
- MATLAB:图像选取局部区域滤波(roicolor、roipoly、roifill、fspecial、roifilt2函数)
对于某些特殊的图像处理,我们不希望将整张图都进行图像处理.这个时候就用到了roicolor.roipoly.roifill.fspecial.roifilt2函数.代码实现过程如下: close al ...
- apache 基本vhost配置 【目的及过程】
转: apache 基本vhost配置 2012年04月18日 09:39:28 chamtianjiao 阅读数:74075 经常使用Apache虚拟主机进行开发和测试,但每次需要配置虚拟主 ...
- 洛谷 P4378 [USACO18OPEN]Out of Sorts S(树状数组求冒泡排序循环次数)
传送门:Problem P4378 https://www.cnblogs.com/violet-acmer/p/9833502.html 要回宿舍休息了,题解明天再补吧. 题解: 定义一数组 a[m ...
- 二叉查找树(BST)、平衡二叉树(AVL树)
二叉查找树(BST) 特殊的二叉树,又称为排序二叉树.二叉搜索树.二叉排序树. 二叉查找树实际上是数据域有序的二叉树,即对树上的每个结点,都满足其左子树上所有结点的数据域均小于或等于根结点的数据域,右 ...
- 使用Nessus漏扫
Nessus号称是世界上最流行的漏洞扫描程序,全世界有超过75000个组织在使用它.该工具提供完整的电脑漏洞扫描服务,并随时更新其漏洞数据库.Nessus不同于传统的漏洞扫描软件,Nessus可同时在 ...
- 安装Cloudera manager Server步骤详解
安装Cloudera manager Server步骤详解 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 本篇博客主要是针对:https://www.cnblogs.com/yin ...