题目描述

  有一棵\(n\)个点的树,还有\(m\)个物品。

  你要把每个物品放在树上的一个点上(两个物品可以放在同一个点)。

  有\(q\)个限制:\(a,b\)两个物品在路上的最短路经过\(c\)。

  要你构造一组合法的方案。

  \(n,m\leq 250\)

题解

  很容易想到2-sat。

  但是把点看成"物品\(x\)放在\(y\)上"会找不到合法解。

  所以要把点看成“物品\(x\)在以\(y\)为根的子树内”,这样根就是必须选的。

  连边的话(下面只列出一半的边):\(x\rightarrow f_x,x\rightarrow !y\)(\(y\)是\(x\)的兄弟)(这些边可以弄一些前缀后缀的点优化)

  和询问有关的:

  1.\(a\neq b\):\((a,x)\rightarrow !(b,x)\)(\(x\)是\(c\)的儿子),\(!(a,c)\rightarrow (b,c)\)。

  2.\(a=b\):\(!(a,c)\rightarrow(a,c)\),\((a,x)\rightarrow !(a,x)\)(\(x\)是\(c\)的儿子)。

  点数为\(O(nm)\)

  边数为\(O(nm^2)\)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
struct graph
{
int h[400010];
int v[40000010];
int t[40000010];
int n;
graph()
{
n=0;
memset(h,0,sizeof h);
}
void add(int x,int y)
{
n++;
v[n]=y;
t[n]=h[x];
h[x]=n;
}
};
graph g;
vector<int> t[260],t2;
int n,m,q;
int id(int x,int y)//x=物品,y=点
{
return (y-1)*m+x;
}
int cnt;
int pre[260],suf[260];
void add0(int k1,int x,int k2,int y)
{
g.add(id(k1,x)*2-1,id(k2,y)*2);
g.add(id(k2,y)*2-1,id(k1,x)*2);
}
void add4(int k1,int x,int k2,int y)
{
g.add(id(k1,x)*2,id(k2,y)*2-1);
g.add(id(k2,y)*2,id(k1,x)*2-1);
}
void add1(int k1,int x,int k2,int y)
{
g.add(id(k1,x)*2-1,id(k2,y)*2-1);
g.add(id(k2,y)*2,id(k1,x)*2);
}
void add2(int k,int x)
{
g.add(id(k,x)*2,id(k,x)*2-1);
}
void add3(int k,int x)
{
g.add(id(k,x)*2-1,id(k,x)*2);
}
int f[300];
int d[300];
void dfs(int x,int fa,int dep)
{
t2.clear();
f[x]=fa;
d[x]=dep;
for(auto v:t[x])
if(v!=fa)
t2.push_back(v);
t[x]=t2;
for(auto v:t[x])
dfs(v,x,dep+1);
}
int b[400010];
int e[400010];
int ti,tot,top;
int st[400010];
int dfn[400010];
int low[400010];
int c[300][300][300];
void dfs(int x)
{
low[x]=dfn[x]=++ti;
st[++top]=x;
b[x]=1;
for(int i=g.h[x];i;i=g.t[i])
{
if(b[g.v[i]]!=2)
{
if(!b[g.v[i]])
dfs(g.v[i]);
low[x]=min(low[x],low[g.v[i]]);
}
}
if(low[x]>=dfn[x])
{
int v;
tot++;
do
{
v=st[top--];
e[v]=tot;
b[v]=2;
}
while(v!=x);
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
freopen("a.out","w",stdout);
#endif
scanf("%d%d%d",&n,&m,&q);
int x,y,z;
for(int i=1;i<n;i++)
{
scanf("%d%d",&x,&y);
t[x].push_back(y);
t[y].push_back(x);
}
dfs(1,0,1);
cnt=n;
for(int i=1;i<=n;i++)
{
if(i!=1)
for(int k=1;k<=m;k++)
add1(k,i,k,f[i]);
int sz=t[i].size();
for(int j=0;j<sz;j++)
{
pre[j]=++cnt;
for(int k=1;k<=m;k++)
add1(k,t[i][j],k,pre[j]);
if(j)
for(int k=1;k<=m;k++)
add1(k,pre[j-1],k,pre[j]);
}
for(int j=sz-1;j>=0;j--)
{
suf[j]=++cnt;
for(int k=1;k<=m;k++)
add1(k,t[i][j],k,suf[j]);
if(j!=sz-1)
for(int k=1;k<=m;k++)
add1(k,suf[j+1],k,suf[j]);
}
for(int j=0;j<sz;j++)
{
if(j)
for(int k=1;k<=m;k++)
add0(k,t[i][j],k,pre[j-1]);
if(j!=sz-1)
for(int k=1;k<=m;k++)
add0(k,t[i][j],k,suf[j+1]);
}
}
for(int i=1;i<=m;i++)
add2(i,1);
memset(b,0,sizeof b);
for(int i=1;i<=q;i++)
{
scanf("%d%d%d",&x,&y,&z);
if(x>y)
swap(x,y);
if(c[x][y][z])
continue;
c[x][y][z]=1;
if(x==y)
{
add2(x,z);
for(auto v:t[z])
add3(x,v);
}
else
{
for(auto v:t[z])
add0(x,v,y,v);
add4(x,z,y,z);
}
}
ti=0;
tot=0;
top=0;
for(int i=1;i<=2*m*cnt;i++)
if(!b[i])
dfs(i);
for(int i=1;i<=m;i++)
{
int ans=1;
for(int j=1;j<=n;j++)
if(e[2*id(i,j)-1]<e[2*id(i,j)])
if(d[j]>d[ans])
ans=j;
printf("%d ",ans);
}
return 0;
}

【XSY2750】Mythological V 2-sat的更多相关文章

  1. 【XSY2786】Mythological VI 数学

    题目描述 有\(1\sim n\)一共\(n\)个数.保证\(n\)为偶数. 你要把这\(2n\)个数两两配对,一共配成\(n\)对.每一对的权值是他们两个数的和. 你想要知道这\(n\)对里最大的权 ...

  2. 【XSY2751】Mythological IV 线性插值

    题目描述 已知\(f(x)\)为\(k\)次多项式. 给你\(f(0),f(1),\ldots,f(k)\),求 \[ \sum_{i=1}^nf(i)q^i \] \(k\leq 500000,n\ ...

  3. 【转】grep -v grep

    1.grep 是查找含有指定文本行的意思,比如grep test 就是查找含有test的文本的行 2.grep -v 是反向查找的意思,比如 grep -v grep 就是查找不含有 grep 字段的 ...

  4. MT【330】u,v,w法

    已知$a^2+b^2+c^2=1$求$abc(a+b+c)$的最小值.(2018辽宁预赛解答压轴题) 不妨设$a+b+c=3u,ab+bc+ca=3v^2,abc=w^3$,令$u^2=tv^2$要求 ...

  5. 【XSY2787】Mythological VII 贪心

    题目描述 有两个指针\(l,r\),初始时\(l=r=k\) 给你\(a_1,\ldots,a_n\),你要移动\(l,r\),\(l\)只能每次向左移一个数,\(r\)只能向右移一个数,要求任意时刻 ...

  6. 【学时总结】◆学时·V◆ 逆元法

    ◆学时·V◆ 逆元法 □算法概述□ 逆元运算是模运算中的一个技巧,一般用于解决模运算的除法问题.模运算对于加.减.乘是有封闭性的,即 (a±b)%m=a%m±b%m,以及 (a×b)%m=a%m×b% ...

  7. 【原创】如何通过-y和-v使用库文件

    在进行仿真时,经常遇到设计代码中需要调用一些标准的库文件,但是在设计的编译列表filelist中却没有相应的库文件,这时为了完成仿真,需要设计人员提供对应的库文件或者库文件所在的路径,然后仿真时将这些 ...

  8. 【pwn】V&N2020 公开赛 simpleHeap

    [pwn]V&N2020 公开赛 simpleHeap 1.静态分析 首先libc版本是ubuntu16的2.23版本,可以去buu的资源处下载 然后checksec一下,保护全开 拖入IDA ...

  9. 【Leetcode】1340. Jump Game V 【动态规划/记忆性搜索】

    Given an array of integers arr and an integer d. In one step you can jump from index i to index: i + ...

随机推荐

  1. Leetcode -- 258 数位相加

    258. Given a non-negative integer num, repeatedly add all its digits until the result has only one d ...

  2. Linux进程与线程的区别

    进程与线程的区别,早已经成为了经典问题.自线程概念诞生起,关于这个问题的讨论就没有停止过.无论是初级程序员,还是资深专家,都应该考虑过这个问题,只是层次角度不同罢了.一般程序员而言,搞清楚二者的概念, ...

  3. PS 十分钟教你做出文字穿插效果

  4. PS调出通透唯美阳光外景女生照片

    1.稍微增加了一点曝光度,让照片更明亮. 2.对比度的话我现在比习惯加一点,而且 一般导入PS之后我还会按照片情况去加对比度. 3.高光的部分一般会拉回来一点,根据照片调. 4.阴影部分加一点的话会让 ...

  5. RabbitMQ 安装与使用

    RabbitMQ 安装与使用   前言 吃多了拉就是队列,吃饱了吐就是栈 使用场景 对操作的实时性要求不高,而需要执行的任务极为耗时:(发送短信,邮件提醒,更新文章阅读计数,记录用户操作日志) 存在异 ...

  6. 课程存储校对:程序设计思想、源程序代码、运行结果截图,以及开发过程中的项目计划日志、时间记录日志、缺陷记录日志(PSP0级记录)。

    1.程序设计思想 ⑴将JDBC驱动jar包导入到WEB-INF的lib文件夹下 ⑵建立数据库,在数据库中建表,分别将课程名称.任课教师及上课地点录入到列中 ⑶首先写出加载驱动.关闭资源的工具类和异常处 ...

  7. 【问题解决方案】本地代码文件上传到GitHub里中文乱码问题

    刚刚学完Git并试着上传了我的化石Java代码到远程库,表面一切和谐,然而.. 真让人大惊失色.. step1-检查浏览器是否是utf-8(谷歌默认是) step2-在本地编辑器设置 (按理说,not ...

  8. IdentityServer4【QuickStart】之使用ResourceOwnerPassword流程来保护API

    使用ResourceOwnerPassword流程来保护API OAuth2.0中的ResourceOwnerPassword授权流程允许一个客户端发送username和password到token服 ...

  9. mysql_linux(centos7 mysql 5.7.19)

    centos7  mysql 5.7.19安装 1.解压文件 [root@centos3 ~]# tar -zxvf mysql-5.7.19-linux-glibc2.12-x86_64.tar.g ...

  10. [转帖]分布式Unique ID的生成方法一览

    分布式Unique ID的生成方法一览 http://www.importnew.com/22211.html 分布式的Unique ID的用途如此广泛,从业务对象Id到日志的TraceId,本文总结 ...