CF1326G 题解
题意:
蛛网树是一颗平面树,满足点是该树的凸包的顶点上等价于其是叶子。
给定一个平面树,求有多少种对点集的划分,使得每个划分出来的集合都是蛛网树。
Solution
考虑树形 dp。设 \(f_u\) 是 \(u\) 子树内的划分方案。先考虑两种特殊情况,以 \(u\) 为最浅点的蛛网树只有 \(1,2\) 个点,是容易转移的(因为后面的凸包转移是按边所以这些不会统计到)。
先考虑一个凸包带来的贡献最后应当计算所有凸包带权的和累加到 f 上。设凸包为 \(S\),其带的权应为:
\]
考虑拆一下贡献。
把到叶子的线延长划分出若干区域。把每个区域内的贡献乘起来就可以了。
中间的那些点一定是在树上的路径(判断时有一些细节,不是半平面交起来!)。直接乘起来即可。这样,就解决了计算权值的问题。
还需要知道:哪些点对有贡献?即哪些点对可能成为相邻的叶子?显然,树上路径点必须在连边的一侧(不妨统一设为左侧),然后根据原树上边转移才能保证没有问题。具体来说,不是按照叶子转移,而是先对子树内的边标号,双向边两个方向不同,然后按照相邻叶子在原树上的起始边转移。
这里的转移类似于 P2924 的转移,先把向量排序,再枚举开始的边和按顺序枚举向量转移,叠加答案即可(注意取消掉只有自己的贡献)。
A 是排序后的向量集合。bh 是边的编号,P 向量的 d 是权值,F,S 是开始边和终止边。x,y 是枚举的起点边。这样的起点边当然必须在某个选定象限内。
for(int i=1;i<=tot;i++)gg[i]=0;
gg[bh[x][y]]=1;
for(auto P:A)(gg[P.F]+=gg[P.S]*P.d)%=mod;
(gg[bh[x][y]]+=mod-1)%=mod;
(f[u]+=gg[bh[x][y]])%=mod;
这样的转移显然是 \(O(n^3)\) 的。
为什么不能按点?可以看四号样例的图:
按照原理来讲,不应该有下面这个凸包:
但是按点的统计就不能避免这种情况。根本原因是,点转移不能区分一个点是否被真正当成叶子,像这个 A 点就连了两条边。容易发现按边就不会出任何问题。
最后还有一个问题:这个凸包必须存在一个相邻点对,满足他们在树上的路径包含当前处理 f 数组的 \(u\),实际上就是 \(u\) 在凸包叶子的虚树上。这个很容易保证,dp 时搞一下或者容斥一下均可。
代码在处理权值的时候参考了 std(因为之前一直写的是在半平面交内还能过 21 个点……)。
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=105,mod=998244353;
struct pt{int x,y;}p[maxn];
pt operator -(pt a,pt b){return {a.x-b.x,a.y-b.y};}
int operator ^(pt a,pt b){return a.x*b.y-a.y*b.x;}
int operator *(pt a,pt b){return a.x*b.x+a.y*b.y;}
int f[maxn],val[maxn][maxn];
#define VI vector<int>
VI lft[maxn][maxn],e[maxn],cur,Ares,E[maxn];
int n,T,dep[maxn];
void dfs(int u,int fa){
cur.push_back(u);
if(u==T)Ares=cur;
for(auto v:E[u]){
if(v==fa)continue;
dfs(v,u);
}
cur.pop_back();
}
VI getpath(int x,int y){
cur.clear();T=y;dfs(x,0);
return Ares;
}
bool check(pt a,pt b,pt c){
return ((b-a)^(c-a))>0;
}
bool good[maxn][maxn];
void dfs2(int u){
cur.push_back(u);
for(auto v:e[u])dfs2(v);
}
VI getsubt(int u){
cur.clear();
dfs2(u);
return cur;
}
int g[maxn];
struct vec{int u,v,d,S,F,ex;};
bool pd(pt a,pt b){
return 1-(b.y>a.y||(b.y==a.y&&b.x>=a.x));
}
bool pd(pt a){
return pd((pt){0,0},a);
}
bool operator <(vec a,vec b){
pt A=p[a.v]-p[a.u],B=p[b.v]-p[b.u];
if(pd(A)!=pd(B))return pd(A)<pd(B);
return (A^B)>0;
}
int Find(int u,const VI &A){
for(auto v:A)if(v==u)return 1;
return 0;
}
bool fat(int x,int y){
VI chain=getpath(x,y);
if(chain.size()==abs(dep[x]-dep[y])+1)return 1;
return 0;
}
bool pd2(pt a,pt b){
if((a^b)!=0)return (a^b)<0;
return (a*b)<0;
}
bool PD(pt a,pt b,pt c){
int x=pd2(a,b),y=pd2(a,c);
if(x!=y)return x<y;
return (b^c)>0;
}
bool dm[maxn][maxn],ckd[maxn][maxn];
vector<int> G[maxn];
int bh[maxn][maxn],gg[maxn*maxn];
void dp(int u){
int prod=1;
for(auto v:e[u]){
dp(v);
(prod*=f[v])%=mod;
}
f[u]=prod;
for(auto v:e[u]){
int p=1;
for(auto w:e[v])(p*=f[w])%=mod;
for(auto v2:e[u])if(v2!=v)(p*=f[v2])%=mod;
(f[u]+=p)%=mod;
}
VI sub=getsubt(u);
for(auto u:sub)G[u].clear();
int tot=0;
for(auto u:sub){
for(auto v:e[u]){
G[u].push_back(v);
G[v].push_back(u);
bh[u][v]=++tot;
bh[v][u]=++tot;
}
}
vector<vec> A;
for(auto x:sub){
for(auto y:sub){
if(x==y||!good[x][y]||dm[x][y])continue;
if(((p[y]-p[x])^(p[u]-p[x]))<0)continue;
VI path=getpath(x,y);int N=path.size()-1,d=1;
for(int i=0;i<=N;i++){
int v=path[i];
pt A,B;
if(i==0)A=p[v]-p[path[i+1]];
else A=p[path[i-1]]-p[v];
if(i==N)B=p[v]-p[path[i-1]];
else B=p[path[i+1]]-p[v];
for(auto w:e[v]){
if(!PD(A,p[w]-p[v],B))continue;
if((i>0&&w==path[i-1])||(i<N&&w==path[i+1]))continue;
(d*=f[w])%=mod;
}
}
bool tp=0;
if(Find(u,path))tp=1;
A.push_back({x,y,d,bh[path[0]][path[1]],bh[path[N]][path[N-1]],tp});
}
}
sort(A.begin(),A.end());
for(auto x:sub){
for(auto y:G[x]){
if(pd(p[x],p[y]))continue;
for(int i=1;i<=tot;i++)gg[i]=0;
gg[bh[x][y]]=1;
for(auto P:A)(gg[P.F]+=gg[P.S]*P.d)%=mod;
(gg[bh[x][y]]+=mod-1)%=mod;
(f[u]+=gg[bh[x][y]])%=mod;
}
}
for(auto x:sub){
for(auto y:G[x]){
if(pd(p[x],p[y]))continue;
for(int i=1;i<=tot;i++)gg[i]=0;
gg[bh[x][y]]=1;
for(auto P:A)if(P.ex==0)(gg[P.F]+=gg[P.S]*P.d)%=mod;
(gg[bh[x][y]]+=mod-1)%=mod;
(f[u]+=mod-gg[bh[x][y]])%=mod;
}
}
}
int fa[maxn];
void dfs1(int u,int f){
fa[u]=f;dep[u]=dep[f]+1;
for(auto v:e[u]){
if(v==f)continue;
dfs1(v,u);
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<=n;i++)cin>>p[i].x>>p[i].y;
for(int i=1;i<n;i++){
int u,v;cin>>u>>v;
e[v].push_back(u);
e[u].push_back(v);
E[u].push_back(v);
E[v].push_back(u);
dm[u][v]=dm[v][u]=1;
}
dfs1(1,0);
for(int i=2;i<=n;i++){
VI A;
for(auto u:e[i])if(u!=fa[i])A.push_back(u);
swap(A,e[i]);
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i==j||dm[i][j])continue;
VI chain=getpath(i,j);
bool ck=1;
for(auto u:chain)
if(u!=i&&u!=j&&!check(p[i],p[j],p[u])){
ck=0;break;
}
good[i][j]=ck;
}
}
dp(1);
cout<<f[1]<<endl;
return 0;
}
CF1326G 题解的更多相关文章
- 2016 华南师大ACM校赛 SCNUCPC 非官方题解
我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...
- noip2016十连测题解
以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...
- BZOJ-2561-最小生成树 题解(最小割)
2561: 最小生成树(题解) Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1628 Solved: 786 传送门:http://www.lyd ...
- Codeforces Round #353 (Div. 2) ABCDE 题解 python
Problems # Name A Infinite Sequence standard input/output 1 s, 256 MB x3509 B Restoring P ...
- 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解
题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...
- 2016ACM青岛区域赛题解
A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Jav ...
- poj1399 hoj1037 Direct Visibility 题解 (宽搜)
http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...
- 网络流n题 题解
学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...
- CF100965C题解..
求方程 \[ \begin{array}\\ \sum_{i=1}^n x_i & \equiv & a_1 \pmod{p} \\ \sum_{i=1}^n x_i^2 & ...
- JSOI2016R3 瞎BB题解
题意请看absi大爷的blog http://absi2011.is-programmer.com/posts/200920.html http://absi2011.is-programmer.co ...
随机推荐
- Ubuntu下xrdp登陆故障解决方案
故障描述: Ubuntu使用xrdp远程桌面运行一段时间后,出现登陆错误: xrdp_mm_process_login_response: login failed 原因分析: 远程桌面没有正确关闭所 ...
- 使用 JsonSchema 校验 JSON数据
有时候JSON 数据格式需要校验是否合法,我们可以使用 JsonSchema 来校验数据是否合法. 引入 pom.xml https://json-schema.org/ <dependency ...
- 生成条形码二维码DataMatrix条码.EAN码.39码.交叉25码.UPC码.128码.93码.ISBN码.Codabar等
1.引用Spire.Barcode 在Nuget包中安装Spire.Barcode 2.生成条形码 //创建 BarcodeSettings对象 BarcodeSettings settings = ...
- Web API 控制器的行为和操作方法的属性
ControllerBase 类 Web API 包含一个或多个派生自 ControllerBase 的控制器类. Web API 项目模板提供了一个入门版控制器 [ApiController] [R ...
- openEuler欧拉安装Jenkins并修改构建workspace路径
一.系统优化 关闭防火墙 systemctl stop firewalld systemctl disable firewalld 关闭selinux sed -ri 's/SELINUX=enfo ...
- 【Python】【Pandas】使用concat添加行
添加行 t = pd.DataFrame(columns=["姓名","平均分"]) t = t.append({"姓名":"小红 ...
- SprinfBoot报警告WARNING: An illegal reflective access operation has occurred
警告如图所示,该警告是因为jdk版本太高(我用的是10.0,据说9.0的也会这样),具体的原理还没有研究,它不影响项目的正常运行,但是看着很糟心有木有~~~~ 解决方案是把项目jdk降低到1.8及以下 ...
- Qt开发经验小技巧181-185
Qt天生就是linux的,从linux开始发展起来的,所以不少Qt程序员经常的开发环境是linux,比如常用的ubuntu等系统,整理了一点常用的linux命令. 命令 功能 sudo -s 切换到管 ...
- FFmpeg中的色彩空间与像素格式2-RGB/YUV色彩空间
cnblogs 网站将文本J:a:b渲染成了J️b.是否可通过设置博客后台解决此问题?有知道的同学请留言指点一下,谢谢. FFmpeg 中的色彩与像素系列文章如下: [1]. FFmpeg中的色彩空间 ...
- [转]idea2021.1破解版 附安装教程免激活码
参看链接:http://www.ddooo.com/softdown/190256.htm 百度网盘地址:https://pan.baidu.com/share/init?surl=qwywmPK-F ...