CF1111E Tree 动态规划+LCT
这个题的思路非常好啊.
我们可以把 $k$ 个点拿出来,那么就是求将 $k$ 个点划分成不大于 $m$ 个集合的方案数.
令 $f[i][j]$ 表示将前 $i$ 个点划分到 $j$ 个集合中的方案数.
那么有 $f[i][j]=f[i-1][j-1]+f[i-1][j]*(j-fail[i])$,其中 $fail[i]$ 代表 $i$ 到根这条路径上祖先数量.
而 $fail[i]$ 的求解方式有:虚数统计/树上数据结构维护路径和,这里选择了用 LCT 来维护.
code:
#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
#define N 100007
#define ll long long
#define mod 1000000007
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
namespace LCT
{
#define lson t[x].ch[0]
#define rson t[x].ch[1]
struct node
{
int ch[2],f,rev,sum,val;
}t[N];
int sta[N];
int get(int x)
{
return t[t[x].f].ch[1]==x;
}
int isrt(int x)
{
return !(t[t[x].f].ch[0]==x||t[t[x].f].ch[1]==x);
}
void pushup(int x)
{
t[x].sum=t[lson].sum+t[rson].sum+t[x].val;
}
void mark(int x)
{
t[x].rev^=1;
swap(lson,rson);
}
void pushdown(int x)
{
if(t[x].rev)
{
if(lson) mark(lson);
if(rson) mark(rson);
t[x].rev=0;
}
}
void rotate(int x)
{
int old=t[x].f,fold=t[old].f,which=get(x);
if(!isrt(old)) t[fold].ch[t[fold].ch[1]==old]=x;
t[old].ch[which]=t[x].ch[which^1],t[t[old].ch[which]].f=old;
t[x].ch[which^1]=old,t[old].f=x,t[x].f=fold;
pushup(old),pushup(x);
}
void splay(int x)
{
int v=0,u=x,fa;
for(sta[++v]=u;!isrt(u);u=t[u].f) sta[++v]=t[u].f;
for(;v;--v) pushdown(sta[v]);
for(u=t[u].f;(fa=t[x].f)!=u;rotate(x))
{
if(t[fa].f!=u)
rotate(get(fa)==get(x)?fa:x);
}
}
void Access(int x)
{
for(int y=0;x;y=x,x=t[x].f)
{
splay(x);
rson=y;
pushup(x);
}
}
void makeroot(int x)
{
Access(x),splay(x),mark(x);
}
void split(int x,int y)
{
makeroot(x),Access(y),splay(y);
}
void add(int x,int v)
{
Access(x),splay(x);
t[x].val+=v,pushup(x);
}
int query(int x)
{
Access(x),splay(x);
return t[x].sum;
}
#undef lson
#undef rson
};
int n,edges;
int hd[N],to[N<<1],nex[N<<1],f[N],A[N],dp[N][302];
void add(int u,int v)
{
nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;
}
void dfs(int u,int ff)
{
LCT::t[u].f=ff;
for(int i=hd[u];i;i=nex[i])
{
int v=to[i];
if(v==ff) continue;
dfs(v,u);
}
}
int main()
{
// setIO("input");
int i,j,q;
scanf("%d%d",&n,&q);
for(i=1;i<n;++i)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y),add(y,x);
}
dfs(1,0);
for(i=1;i<=q;++i)
{
int k,m,r,flag=0;
scanf("%d%d%d",&k,&m,&r);
LCT::makeroot(r);
for(j=1;j<=k;++j)
{
scanf("%d",&A[j]);
LCT::add(A[j],1);
}
for(j=1;j<=k;++j)
{
f[j]=LCT::query(A[j])-1;
if(f[j]>m) flag=1;
}
for(j=1;j<=k;++j) LCT::add(A[j],-1);
if(flag) printf("0\n");
else
{
sort(f+1,f+1+k);
dp[1][1]=1;
for(j=2;j<=k;++j)
{
for(int p=1;p<=min(j,m);++p)
{
dp[j][p]=0;
if(p<f[j]) dp[j][p]=dp[j-1][p-1];
else dp[j][p]=(ll)(dp[j-1][p-1]+1ll*(p-f[j])*dp[j-1][p]%mod)%mod;
}
}
int ans=0;
for(j=1;j<=m;++j) ans=(ans+dp[k][j])%mod;
printf("%d\n",ans);
}
}
return 0;
}
CF1111E Tree 动态规划+LCT的更多相关文章
- CF1111E Tree 树链剖分,DP
CF1111E Tree 过年了,洛咕还没爬这次的题,先放个CF的链接吧. 补个LG传送门. 对于每个询问点\(x\),设它的祖先即不能和它放在同一个集合中的点的个数为\(f[x]\),设\(dp[i ...
- BZOJ 3282 Tree Link-Cut-Tree(LCT)
题目大意: 给定N个点以及每一个点的权值,要你处理接下来的M个操作.操作有4种.操作从0到3编号.点从1到N编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和.保证x到y ...
- 72【leetcode】经典算法- Lowest Common Ancestor of a Binary Search Tree(lct of bst)
题目描述: 一个二叉搜索树,给定两个节点a,b,求最小的公共祖先 _______6______ / \ ___2__ ___8__ / \ / \ 0 _4 7 9 / \ 3 5 例如: 2,8 - ...
- QTREE5 - Query on a tree V——LCT
QTREE5 - Query on a tree V 动态点分治和动态边分治用Qtree4的做法即可. LCT: 换根后,求子树最浅的白点深度. 但是也可以不换根.类似平常换根的往上g,往下f的拼凑 ...
- HDU 6394 Tree 分块 || lct
Tree 题意: 给你一颗树, 每一个节点都有一个权值, 如果一个石头落在某个节点上, 他就会往上跳这个的点的权值步. 现在有2种操作, 1 把一个石头放在 x 的位置 询问有跳几次才跳出这棵树, 2 ...
- [BZOJ - 2631] tree 【LCT】
题目链接:BZOJ - 2631 题目分析 LCT,像线段树区间乘,区间加那样打标记. 这道题我调了一下午. 提交之后TLE了,我一直以为是写错了导致了死循环. 于是一直在排查错误.直到.. 直到我看 ...
- [BZOJ 3282] Tree 【LCT】
题目链接:BZOJ - 3282 题目分析 这道题是裸的LCT,包含 Link , Cut 和询问两点之间的路径信息. 写代码时出现的错误:Access(x) 的循环中应该切断的是原来的 Son[x] ...
- 【BZOJ】3282: Tree(lct)
http://www.lydsy.com/JudgeOnline/problem.php?id=3282 复习了下lct,发现两个问题.. 1:一开始我以为splay那里直接全部rot(x)就好了,然 ...
- 洛谷.1501.[国家集训队]Tree II(LCT)
题目链接 日常zz被define里没取模坑 //标记下放同线段树 注意51061^2 > 2147483647,要开unsigned int //*sz[]别忘了.. #include < ...
随机推荐
- Ubuntu 16.04 安装 google 输入法
Ubuntu 16.04 安装 google 输入法 在命令行中运行:’sudo apt install fcitx-googlepinyin’ 在 system setting > Langu ...
- CENTOS7下安装和配置MYSQL问题记录
1.安装 下载mysql源安装包 shell> wget http://dev.mysql.com/get/mysql57-community-release-el7-8.noarch.rpm ...
- 安卓新发布机制----app bundle
Android App Bundle是一种改进的应用程序打包方式,能大幅度减少应用体积 unity可以直接导出appbundle,只需要在导出的时候勾选 但是通常项目有sdk离不开java端,我这里是 ...
- Android开发 所需组件配置
1 Unity中的Android Build Support下载 在Unity中的File>Building Settings>Android>Open Download Page, ...
- 【AMAD】django-extensions -- Django框架的自定义命令扩展集合
动机 简介 个人评分 动机 使用Django进行开发的时候,会不会感觉开发工具少了一些.比如每次进入python shell调试的时候要重新import每个model. 简介 django-exten ...
- WDS部署基础知识:使用WDS捕获与应用映像(使用WDS定制系统和应用)
WDS部署基础知识:使用WDS捕获与应用映像(使用WDS定制系统和应用) Win7部署基础知识(8):使用WDS捕获与应用映像 一.添加映像组 使用WDS捕获映像时,会将映像加载到WDS服务器的映像 ...
- flask_sqlalchemy基本设置
from flask import Flask from flask_sqlalchemy import SQLAlchemy #区别 sqlalchemy这是第三方模块不属于flask app = ...
- VS2008编译boost1.53
1. 准备工作:下载boost_1_53_0.zip(bzip2-1.0.6.tar.gz/icu4c-4_4_2-Win32-msvc9.zip/Python-2.5.2.tar.bz2/zlib- ...
- python基础数据类型和初级应用
1.整数: int -- 计算和比较 2 -- 10 推位 8421 20 21 -- 2**7 10 - 2 bit_length 二进制的有效占用位数 # 123 # 计算和比较 # 14 0 # ...
- ProGuard 最全混淆规则说明
Input/Output Options 输入输出选项 -include filename 递归引入目录的配置文件 -basedirectory directoryname -injars class ...