[2018HN省队集训D5T2] party

题意

给定一棵 \(n\) 个点以 \(1\) 为根的有根树, 每个点有一个 \([1,m]\) 的权值.

有 \(q\) 个查询, 每次给定一个大小为 \(c\) 的点集, 点集中的每个点都可以选择若干从自身到所有点的LCA的路径上的点的权值. 要求所有点选取的权值之间都不能重复且每个点选择的权值种类数相等. 求最大的总种类数量.

\(n\le 3\times 10^5,m\le 1000, q\le 5\times 10^4,c\le5\).

题解

注意到 \(m\) 的范围比较小, 我们一点都不显然可以用 std::bitset 来维护某条路径上存在的权值集合.

然后我们如果要暴力判定的话, 可以二分答案/多次增广+Dinic来跑. 从这个过程中可以看出我们实际上要求的是满足一边有 \(c\times k\) 个点另一边有 \(m\) 个点的二分图存在完美匹配的最大的 \(k\).

涉及到完美匹配的判定, 我们有一个玄学定理叫霍尔定理. 大体内容是:

一个二分图 \(G\) 存在完美匹配, 当且仅当 \(X\) 中的任意 \(k\) 个点都至少与 \(Y\) 中的 \(k\) 个点邻接.

不难发现左部的 \(c\times k\) 个点中只有 \(c\) 种邻接关系不同的点, 所以我们 \(2^c\)枚举左部点的子集, 用 std::bitset 取并来计算邻接点个数, 则 \(k\) 的最大值即为邻接点个数与左部点子集大小的比值的最小值.

于是就这么跑就可以了. 代码极为好写.

不过查询路径的时候如果用普通树剖+线段树的话是 \(\log^2\) 的, 注意到我们只会求某个点的祖先到某个点的路径, 也就是说除了最浅的一条链之外其他的链都只取了一个前缀. 于是记录每个点到链顶的前缀和, 最后一次查询用线段树就可以把复杂度降到一个 \(\log\) 了. 然而犯懒没写...不加这个优化跑得也挺快的qwq

参考代码

#include <bits/stdc++.h>

const int MAXV=3e5+10;
const int MAXE=1e6+10;
typedef std::bitset<1024> bits; struct Edge{
int from;
int to;
Edge* next;
};
Edge E[MAXE];
Edge* head[MAXV];
Edge* topE=E; struct Node{
int l;
int r;
bits val;
Node* lch;
Node* rch;
Node(int,int);
bits Query(int,int);
};
Node* N; int n;
int m;
int q;
int clk;
int t[10];
bits b[10];
int a[MAXV];
int dfn[MAXV];
int pos[MAXV];
int prt[MAXV];
int son[MAXV];
int top[MAXV];
int size[MAXV];
int deep[MAXV]; int LCA(int,int);
void DFS(int,int);
bits Query(int,int);
void Insert(int,int);
void DFS(int,int,int); int main(){
scanf("%d%d%d",&n,&m,&q);
for(int i=2;i<=n;i++){
int x;
scanf("%d",&x);
Insert(x,i);
}
for(int i=1;i<=n;i++)
scanf("%d",a+i);
DFS(1,0,0);
DFS(1,1);
N=new Node(1,n);
while(q--){
int c=0;
scanf("%d",&c);
scanf("%d",t);
int lca=t[0];
for(int i=1;i<c;i++){
scanf("%d",t+i);
lca=LCA(lca,t[i]);
}
for(int i=0;i<c;i++)
b[i]=Query(lca,t[i]);
int ans=INT_MAX;
for(int s=1;s<(1<<c);s++){
bits cur;
int cnt=0;
for(int i=0;i<c;i++){
if((1<<i)&s){
++cnt;
cur|=b[i];
}
}
ans=std::min<int>(ans,cur.count()/cnt);
}
printf("%d\n",ans*c);
}
return 0;
} int LCA(int x,int y){
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]])
std::swap(x,y);
x=prt[top[x]];
}
if(deep[x]>deep[y])
std::swap(x,y);
return x;
} bits Query(int x,int y){
bits ans;
while(top[x]!=top[y]){
if(deep[top[x]]<deep[top[y]])
std::swap(x,y);
ans|=N->Query(dfn[top[x]],dfn[x]);
x=prt[top[x]];
}
if(deep[x]>deep[y])
std::swap(x,y);
ans|=N->Query(dfn[x],dfn[y]);
return ans;
} Node::Node(int l,int r):l(l),r(r){
if(l==r)
this->val.set(a[pos[l]]);
else{
int mid=(l+r)>>1;
this->lch=new Node(l,mid);
this->rch=new Node(mid+1,r);
this->val=this->lch->val|this->rch->val;
}
} bits Node::Query(int l,int r){
if(l<=this->l&&this->r<=r)
return this->val;
else{
if(r<=this->lch->r)
return this->lch->Query(l,r);
if(this->rch->l<=l)
return this->rch->Query(l,r);
return this->lch->Query(l,r)|this->rch->Query(l,r);
}
} void DFS(int root,int prt,int deep){
::prt[root]=prt;
::deep[root]=deep;
::size[root]=1;
for(Edge* i=head[root];i!=NULL;i=i->next){
if(i->to!=prt){
DFS(i->to,root,deep+1);
size[root]+=size[i->to];
if(size[i->to]>size[son[root]])
son[root]=i->to;
}
}
} void DFS(int root,int top){
++clk;
::dfn[root]=clk;
::pos[clk]=root;
::top[root]=top;
if(son[root])
DFS(son[root],top);
for(Edge* i=head[root];i!=NULL;i=i->next)
if(i->to!=prt[root]&&i->to!=son[root])
DFS(i->to,i->to);
} inline void Insert(int from,int to){
topE->from=from;
topE->to=to;
topE->next=head[from];
head[from]=topE++;
}

[2018HN省队集训D5T2] party的更多相关文章

  1. [2018HN省队集训D9T1] circle

    [2018HN省队集训D9T1] circle 题意 给定一个 \(n\) 个点的竞赛图并在其中钦定了 \(k\) 个点, 数据保证删去钦定的 \(k\) 个点后这个图没有环. 问在不删去钦定的这 \ ...

  2. [2018HN省队集训D8T1] 杀毒软件

    [2018HN省队集训D8T1] 杀毒软件 题意 给定一个 \(m\) 个01串的字典以及一个长度为 \(n\) 的 01? 序列. 对这个序列进行 \(q\) 次操作, 修改某个位置的字符情况以及查 ...

  3. [2018HN省队集训D8T3] 水果拼盘

    [2018HN省队集训D8T3] 水果拼盘 题意 给定 \(n\) 个集合, 每个集合包含 \([1,m]\) 中的一些整数, 在这些集合中随机选取 \(k\) 个集合, 求这 \(k\) 个集合的并 ...

  4. [2018HN省队集训D6T2] girls

    [2018HN省队集训D6T2] girls 题意 给定一张 \(n\) 个点 \(m\) 条边的无向图, 求选三个不同结点并使它们两两不邻接的所有方案的权值和 \(\bmod 2^{64}\) 的值 ...

  5. [Luogu P4143] 采集矿石 [2018HN省队集训D5T3] 望乡台platform

    [Luogu P4143] 采集矿石 [2018HN省队集训D5T3] 望乡台platform 题意 给定一个小写字母构成的字符串, 每个字符有一个非负权值. 输出所有满足权值和等于这个子串在所有本质 ...

  6. [2018HN省队集训D5T1] 沼泽地marshland

    [2018HN省队集训D5T1] 沼泽地marshland 题意 给定一张 \(n\times n\) 的棋盘, 对于位置 \((x,y)\), 若 \(x+y\) 为奇数则可能有一个正权值. 你可以 ...

  7. [Codeforces 321D][2018HN省队集训D4T2] Ciel and Flipboard

    [Codeforces 321D][2018HN省队集训D4T2] Ciel and Flipboard 题意 给定一个 \(n\times n\) 的矩阵 \(A\), (\(n\) 为奇数) , ...

  8. [2018HN省队集训D1T3] Or

    [2018HN省队集训D1T3] Or 题意 给定 \(n\) 和 \(k\), 求长度为 \(n\) 的满足下列条件的数列的数量模 \(998244353\) 的值: 所有值在 \([1,2^k)\ ...

  9. [2018HN省队集训D1T1] Tree

    [2018HN省队集训D1T1] Tree 题意 给定一棵带点权树, 要求支持下面三种操作: 1 root 将 root 设为根. 2 u v d 将以 \(\operatorname{LCA} (u ...

随机推荐

  1. 编写高质量 JavaScript -- 知识点小记

    一: 团队合作避免JS冲突 脚本中的变量随时存在冲突的风险, 1.   解决办法---用匿名函数将脚本包起来,让变量的作用域控制在匿名函数之内 如: <script type="tex ...

  2. 一个在linux环境执行io操作的bug

    今天项目有了一个奇葩的要求...是什么呢 后台上传了视频后,解析其中的时长,和预览图,并拼接在一起,然而,之东西并不是太麻烦,很快写好了,在本地测试后也没有问题,嗯,发布到测试环境后,一个jar包报错 ...

  3. Tornado长轮询和WebSocket

    Http协议是一种请求响应式协议, 不允许服务端主动向客户端发送信息. 短轮询是一种简单的实现服务端推送消息的解决方案, 客户端以一定间隔自动向服务端发送刷新请求, 服务端返回要推送的消息作为响应. ...

  4. [BJOI 2018]求和

    Description 题库链接 给你一棵 \(n\) 个结点的有根树, \(m\) 次询问这棵树上一段路径上所有节点深度的 \(k\) 次方和. \(1\leq n\leq 300000,1\leq ...

  5. 哪个先执行:@PostConstruct和@Bean的initMethod?

    结论: /** * step1:执行构造函数 * step2:执行使用@PostConstruct注解修饰的方法[如果有多个,则执行顺序不确定] * step3:执行@Bean注解中initMetho ...

  6. Java基础教程(17)--接口

      就像类一样,接口也是引用类型.它可以包含常量,方法签名,默认方法,静态方法和嵌套类型.在接口中,只有默认方法和静态方法有方法体.但不同于类,接口无法实例化,它只能被类实现或被其他接口继承. 一.定 ...

  7. SpringBoot+Swagger2 整合

    SpringBoot+Swagger2四步整合 第一步:添加相关依赖 <parent> <groupId>org.springframework.boot</groupI ...

  8. JSP基础知识点

    JSP(Java Server Page)是主要有Sun公司倡导的一种动态网页技术,利用JSP可以构建跨平台的动态网站 应用,JSP在服务器端带JSP容器的Web服务器中运行.JSP以Java语言为基 ...

  9. SpringMVC配置式开发

    所谓配置式开发是指“处理器类是程序员手工定义,实现了特定接口的类,然后再在SpringMVC 配置文件中对该类进行显示的.明确的注册”的开发方式. 一.处理器映射器HandlerMapping Han ...

  10. MVC 客户端(Memo = "<img src="http://">")中检测到有潜在的危险的 Request.Form 值 的解决方案

    解释定义:ASP.NET为了阻止跨站脚本攻击,会对向服务器端输入的HTML代码进行防御措施,在使用.NET MVC中,可以对validateinput属性设置,但是,有时需要ASP.NET临时关闭这个 ...