vjudge

description

有一棵\(n\)个节点的树和\(m\)只兔子,每只兔子要住在一个点上(可以多只兔子住在同一个点上)。有\(q\)组要求,每组形如“当以\(r\)为根时,兔子\(a\)和兔子\(b\)居住的点的\(\mbox{LCA}\)要是\(x\)”。求一组合法方案,或判断不合法。

\(n,m,q\le250\)

sol

\(\mbox{2-sat}\)。

设\(S(i,j)\)表示\(i\)号兔子是否住在\(j\)节点的子树中。这里的子树是随便选一个点出来当作根的。

一些比较显然的连边(以下连边默认加上逆否命题的连边):

\(\lnot S(i,rt) \to S(i,rt)\)

\(S(i,u) \to S(i,fa_u)\)

\(S(i,u) \to \lnot S(i,v)\)当且仅当\(u,v\)不存在祖孙关系。

然后就需要考虑每组要求了。

这里由于换根,需要对子树特殊处理,方法比较像[BZOJ3083]遥远的国度

\(Case\ 1:x=r\)

那么\(a\)和\(b\)就要在\(x(r)\)的不同子树内,对于\(x\)的每一个儿子\(u\),若\(a,b\)其中一个在子树\(u\)内另外一个就不能在。注意到\(x(r)\)可能不是树根\(rt\),所以\(a,b\)中的其中一个还可能在\(x(r)\)的上方部分。

\(Case\ 2:r\)在\(x\)的子树中(这里是以选定的\(rt\)为根的子树)

设\(r\)在\(y\)的子树中,其中\(y \in son(x)\)。

连边和上一种\(Case\)基本相同,除了\(a,b\)都不能在\(y\)这棵子树中。

\(Otherwise\)

\(a,b\)都必须要在\(x\)的子树中,且不能在相同儿子的子树中。

建完边之后跑\(Tarjan\)就好了。

点数是\(O(n^2)\),边数\(O(n^3)\),总复杂度\(O(n^3)\)。

code

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
int gi(){
int x=0,w=1;char ch=getchar();
while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
if (ch=='-') w=0,ch=getchar();
while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return w?x:-x;
}
const int N = 505;
const int M = 2e7+5;
int n,m,q,fa[N],r[N],a[N],b[N],x[N],pre[N],ft[N],st[N],ed[N],tim,S[N][N],tot=-1;
int to[M],nxt[M],head[N*N],cnt,dfn[N*N],low[N*N],s[N*N],vis[N*N],bel[N*N],scc;
vector<int>ans;
void dfs(int u){
st[u]=++tim;
for (int v=ft[u];v;v=pre[v]) dfs(v);
ed[u]=tim;
}
bool in(int x,int y){//whether x is in y's subtree
return st[x]>=st[y]&&st[x]<=ed[y];
}
void link(int u,int v){
to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
u^=1;v^=1;swap(u,v);
to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;
}
void Tarjan(int u){
dfn[u]=low[u]=++tim;vis[s[++s[0]]=u]=1;
for (int e=head[u];e;e=nxt[e])
if (!dfn[to[e]]) Tarjan(to[e]),low[u]=min(low[u],low[to[e]]);
else if (vis[to[e]]) low[u]=min(low[u],dfn[to[e]]);
if (dfn[u]==low[u]){
++scc;int x;
do x=s[s[0]--],vis[x]=0,bel[x]=scc; while (x^u);
}
}
void work(){
for (int i=1;i<=n;++i) pre[i]=ft[fa[i]],ft[fa[i]]=i;
dfs(0);
for (int i=0;i<m;++i)
for (int j=0;j<=n;++j)
S[i][j]=++tot,++tot;
for (int i=0;i<m;++i){
link(S[i][0]^1,S[i][0]);
for (int u=1;u<=n;++u) link(S[i][u],S[i][fa[u]]);
for (int u=1;u<=n;++u)
for (int v=u+1;v<=n;++v)
if (!in(u,v)&&!in(v,u)) link(S[i][u],S[i][v]^1);
}
for (int i=0;i<q;++i){
if (x[i]==r[i]){
link(S[a[i]][x[i]]^1,S[b[i]][x[i]]);
for (int u=ft[x[i]];u;u=pre[u]) link(S[a[i]][u],S[b[i]][u]^1);
}
else if (in(r[i],x[i])){
int y=r[i];while (fa[y]!=x[i]) y=fa[y];
link(S[a[i]][y],S[a[i]][y]^1);
link(S[b[i]][y],S[b[i]][y]^1);
link(S[a[i]][x[i]]^1,S[b[i]][x[i]]);
for (int u=ft[x[i]];u;u=pre[u]) if (u!=y) link(S[a[i]][u],S[b[i]][u]^1);
}
else{
link(S[a[i]][x[i]]^1,S[a[i]][x[i]]);
link(S[b[i]][x[i]]^1,S[b[i]][x[i]]);
for (int u=ft[x[i]];u;u=pre[u]) link(S[a[i]][u],S[b[i]][u]^1);
}
}
for (int i=tim=0;i<=tot;++i) if (!dfn[i]) Tarjan(i);
for (int i=0;i<=tot;i+=2) if (bel[i]==bel[i^1]) return;
for (int i=0;i<m;++i){
int res=0;
for (int j=1;j<=n;++j)
if (bel[S[i][j]]<bel[S[i][j]^1]) res=j;
ans.push_back(res);
}
return;
}
class HiddenRabbits{
public:
vector<int> whereAreTheRabbits(vector<int>ff,int mm,vector<int>rr,vector<int>aa,vector<int>bb,vector<int>xx){
n=ff.size();q=rr.size();m=mm;
for (int i=1;i<=n;++i) fa[i]=ff[i-1];
for (int i=0;i<q;++i) r[i]=rr[i],a[i]=aa[i],b[i]=bb[i],x[i]=xx[i];
work();return ans;
}
};

[TopCoder14647]HiddenRabbits的更多相关文章

  1. noi.ac上的一套(假)NOI题

    noi.ac上的一套(假)NOI题 本来想着可以刷点通过量的,结果发现好像并不是这样的. 整数 description 给你\(n,p\),要你求\(\sum_{k=1}^n\sum_{i=1}^k\ ...

随机推荐

  1. 文件下载—SSM框架文件下载

    1.准备上传下载的api组件 <dependency> <groupId>commons-io</groupId> <artifactId>common ...

  2. 在Java中关于二进制、八进制、十六进制的辨析

    八进制数中不可能出7以上的阿拉伯数字.但如果这个数是123.是567,或12345670,那么它是八进制数还是10进制数?单从数字的角度来讲都有可能! 八进制 所以在Java中规定,一个数如果要指明它 ...

  3. Linux_Chrome出现Adobe Flash Player is out of date解决方法

    在安装Google的Chrome后都有出现Adobe Flash Player is out of date的问题. Chrome浏览器用的播放器插件是PepperFlashPlayer.而且是内置的 ...

  4. 【android】如何实现猿题库题目的排版

    最近我们的产品来了个新的模块,类似猿题库一样,给学生做题提高成绩的. 要求如下: 1:支持单选.多选.填空题 2:支持图片文字混排 3:输入框有交互,排版精致美观 4:为了体验优化,不能使用网页实现效 ...

  5. MapReduce: map读取文件的过程

    我们的输入文件 hello0, 内容如下: xiaowang 28 shanghai@_@zhangsan 38 beijing@_@someone 100 unknown 逻辑上有3条记录, 它们以 ...

  6. 20145301《网络对抗》Exp2 后门原理与实践

    20145301<网络对抗>Exp2 后门原理与实践 基础问题回答 例举你能想到的一个后门进入到你系统中的可能方式? 系统或者某些软件自身留下的后门. 钓鱼网站等非正规网站上捆绑下载 例举 ...

  7. 20145326 《Java程序设计》第9周学习总结

    20145326 <Java程序设计>第9周学习总结 教材学习内容总结 第十六章 一.JDBC入门 1.JDBC简介 JDBC是用于执行SQL的解决方案,开发人员使用JDBC的标准接口,数 ...

  8. 使用Xshell连接Ubuntu详解

    Xshell是一个安全终端模拟软件,可以进行远程登录.我使用XShell的主要目的是在Windows环境下登录Linux终端,传输一些大文件到Linux环境上去. 1.下载安装xshell客户端,在安 ...

  9. pairs 和 ipairs异同

    同:都是能遍历集合(表.数组) 异:ipairs 仅仅遍历值,按照索引升序遍历,索引中断停止遍历.即不能返回 nil,只能返回数字 0,如果遇到 nil 则退出.它只能遍历到集合中出现的第一个不是整数 ...

  10. Postman模拟json传参

    首先在headers中,设置Content-Type为applicationon/json,如图: 然后再body中,选择raw,写入json数据结构,如图: