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 < ...
随机推荐
- js 闭包解决方案
相比很多人都遇见过这样的情况: 给一个ul的所有li绑定行为,在点击时获取其index. 假设结构如下: <body> <ul> <li>0</li> ...
- 有关face的好文MARK集
Single Stage Headless Face Detector 据说已经超过了tiny face DDFD <Multi-view Face Detection Using Deep C ...
- Winform之跨线程更新UI
Winform之跨线程更新UI 使用`Invoke`或者`BeginInvoke`与UI线程交互示例 参考及源码 使用Invoke或者BeginInvoke与UI线程交互示例 private void ...
- PHP-T
TP5目录结构 ├─application 应用目录 ├─extend 扩展类库目录(可定义) ├─public 网站对外访问目录 ├─runtime 运行时目录(可定义) ├─vendor 第三方类 ...
- HCL试验六
交换机R1: syssysname R1interface loopback 0ip add 192.168.10.1 24quinterface g0/0ip address 10.1.1.1 30 ...
- 再谈Java数据结构—分析底层实现与应用注意事项
在回顾js数据结构,写<再谈js对象数据结构底层实现原理-object array map set>系列的时候,在来整理下java的数据结构. java把内存分两种:一种是栈内存,另一种是 ...
- Jenkins中shell-script执行报错sh: line 2: npm: command not found
<1>本地执行npm run build--正常 <2>查看环境变量--正常 [root@localhost bin]# echo $PATH /usr/local/node/ ...
- 【监控实践】【4.4】使用DMV和函数监控数据库状态和资源使用
1.查看当前实例运行进程 -- 核心DMV.函数.系统SP:/* 所有进程请求:sys.dm_exec_requests 所有进程与连接:sys.sysprocesses 系统函数,查看sql:sys ...
- 【转帖】Linux上,最常用的一批命令解析(10年精选)
Linux上,最常用的一批命令解析(10年精选) https://juejin.im/post/5d134fbfe51d4510727c80d1 写的挺好呢 Linux这么多命令,通常会让初学者望而生 ...
- 云数据库 Redis 版
首先观看视频简介 云数据库 Redis 版是一项易于部署和管理的按需数据库服务,与 Redis 协议兼容.云数据库 Redis 版通过从内存缓存中检索数据而提供高速数据读写功能,并通过同时使用内存和硬 ...