【loj3056】【hnoi2019】多边形
题目
描述
给出一个 \(n\) 个点的多边形初始的三角剖分;
一次合法的旋转定义为 \((a,b,c,d)\) ,满足 \(a<b<c<d\) ;
并且存在边\((a,b)(b,c)(c,d)(d,a)(a,c)\) ,将 \((a,c) - > (b,d)\) ;
简化后用\((a,c)\)描述一次旋转;
给出 \(m\) 个旋转操作,表示每次从初始状态 \(S_0\) 旋转成 \(S_i\) ;
询问对于 \(S_0 - S_m\) 到不能旋转的最少的步数以及方案数;
范围
$ 3 \le n \le 10^5 \ , \ 0 \le m \le 10^5 $ ;
题解
无法再旋转的情况为所有点的某一个端点都是 \(n\) , 否则所有连向 \(n\) 的边会将所有的多边形划分成很多部分,每个部分相互独立,并且每个部分里面一定可以再次移动。我们知道答案的一个下界是两个端点都不为 \(n\) 的线段条数,这个下界是可以达到的:可以发现每部分里面所有的区间形成了一个二叉树的结构,每次从根节点开始操作旋转,可以直接让根的某个端点到 \(n\),此时左右次数变成了新的两个独立的部分,再继续操作其左右子树。
接下来将每条连线 \((a,b)\) 看成线段,单调栈求出这个二叉树森林,显然最小步数==节点数 。 考虑方案,对于每一个二叉树,先转子树是无效的。所以合法的方案=> <优先选根,再选左右子树> 方案数是
。将二叉森林组合起来类似地乘以一个组合数即可;加入修改,对于一次从 \(S_0\) 的改变,对旋转线段对应的点 \(u\) ,分两种情况讨论:
- \(u\) 为某个二叉树的根,最小次数--,删去根,左右儿子被分裂成了两个新的子树统计方案;
- 否则由于要合法一定是父亲的左儿子,最小次数不变,left-rotate(u) 之后统计方案(可以自己画图。。);
均可以只考虑变化量 \(O(1)\) 做到,考虑到要lower_bound旋转线段的标号:\(O(n \log n)\) ;
最近状态好迷啊,交了一发$WA $ 了,改了半天发现没取模TAT,点开博客看看其他人的做法发现yyb神仙也没有取模OVO ;
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=200010,mod=1e9+7;
int Case,n,m,cnt,st[N],top,ls[N],rs[N],fa[N],sz[N],id[N],pre=1,fac[N],inv[N],iv[N];
struct data{
int l,r;
data(int _l=0,int _r=0):l(_l),r(_r){};
bool operator <(const data&A)const{return r==A.r?l>A.l:r<A.r;}
}A[N];
char gc(){
static char*p1,*p2,s[1000000];
if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin);
return(p1==p2)?EOF:*p1++;
}
int rd(){
int x=0;char c=gc();
while(c<'0'||c>'9')c=gc();
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+c-'0',c=gc();
return x;
}
char ps[1000000],*pp=ps;
void push(char x){
if(pp==ps+1000000)fwrite(ps,1,1000000,stdout),pp=ps;
*pp++=x;
}
void flush(){fwrite(ps,1,pp-ps,stdout);pp=ps;}
void write(int x){
static int sta[20],top;
if(!x){push('0');return;}
while(x)sta[++top]=x%10,x/=10;
while(top)push(sta[top--]^'0');
}
int cal(int x,int y){return 1ll*fac[x+y]*inv[x]%mod*inv[y]%mod;}
int ical(int x,int y){return 1ll*inv[x+y]*fac[x]%mod*fac[y]%mod;}
void pushup(int x){
int l=ls[x],r=rs[x];
sz[x]=sz[l]+sz[r]+1;
pre=1ll*pre*cal(sz[l],sz[r])%mod;
}
int mfy1(int x){
int re=pre,l=ls[x],r=rs[x];
re=1ll*re*ical(cnt-sz[x],sz[x])%mod*ical(sz[l],sz[r])%mod;
re=1ll*re*cal(cnt-sz[x],sz[l])%mod*cal(cnt-1-sz[r],sz[r])%mod;
return re;
}
int mfy2(int x){
int re=pre,y=fa[x];
re=1ll*re*ical(sz[ls[y]],sz[rs[y]])%mod*ical(sz[ls[x]],sz[rs[x]])%mod;
re=1ll*re*cal(sz[y]-1-sz[ls[x]],sz[ls[x]])%mod*cal(sz[rs[x]],sz[rs[y]])%mod;
return re;
}
int main(){
// freopen("polygon.in","r",stdin);
// freopen("polygon.out","w",stdout);
Case=rd();n=rd();
iv[1]=1;for(int i=2;i<=n;++i)iv[i]=(ll)(mod-mod/i)*iv[mod%i]%mod;
for(int i=fac[0]=inv[0]=1;i<=n;++i){
fac[i]=(ll)fac[i-1]*i%mod;
inv[i]=(ll)inv[i-1]*iv[i]%mod;
}
for(int i=1;i<=n-3;++i){
A[i].l=rd(),A[i].r=rd();
if(A[i].l>A[i].r)swap(A[i].l,A[i].r);
}
sort(A+1,A+n-2);
for(int i=1;i<=n-3;++i){
if(A[i].r==n)break;
id[i]=++cnt;
while(top&&A[st[top]].l>=A[i].l){
if(A[st[top]].l==A[i].l)ls[cnt]=id[st[top--]],fa[ls[cnt]]=cnt;
else rs[cnt]=id[st[top--]],fa[rs[cnt]]=cnt;
}
pushup(cnt);st[++top]=i;
}
for(int i=1,tmp=0;i<=top;++i){
int t=sz[id[st[i]]];
pre=1ll*pre*cal(tmp,t)%mod;
tmp+=t;
}
m=rd();
write(cnt);if(Case){push(' ');write(pre);}push('\n');
for(int i=1,x,y,p,ans1,ans2;i<=m;++i){
x=rd(),y=rd();if(x>y)swap(x,y);
p = id[ lower_bound(A+1,A+n-2,data(x,y)) - A ];
if(!fa[p]){ans1=cnt-1;ans2=mfy1(p);}
else {ans1=cnt;ans2=mfy2(p);}
write(ans1);if(Case){push(' ');write(ans2);}push('\n');
}
flush();
return 0;
}
【loj3056】【hnoi2019】多边形的更多相关文章
- 【BZOJ5491】[HNOI2019]多边形(模拟,组合计数)
[HNOI2019]多边形(模拟,组合计数) 题面 洛谷 题解 突然特别想骂人,本来我考场现切了的,结果WA了几个点,刚刚拿代码一看有个地方忘记取模了. 首先发现终止态一定是所有点都向\(n\)连边( ...
- HNOI2019 多边形 polygon
HNOI2019 多边形 polygon https://www.luogu.org/problemnew/show/P5288 这题镪啊... 首先堆结论: 显然终止状态一定是所有边都连向n了 根据 ...
- luogu P5288 [HNOI2019]多边形
传送门 这是什么神仙操作... 首先要注意一些性质.首先每一个\((x,n)\)的边可以把当前多边形分成两半,这两半的操作是独立的.然后对于某一个没有\((x,n)\)的边的多边形,最优操作是唯一的. ...
- 【洛谷5288】[HNOI2019] 多边形(二叉树模型)
点此看题面 大致题意: 给你一个多边形,用若干不重合.不相交的线段将其划分为若干三角形区域,并定义旋转操作\((a,c)\)为选定\(4\)个点\(a,b,c,d\)满足\(a<b<c&l ...
- [HNOI2019]多边形[二叉树建模、组合计数]
题意 题目链接 分析 不难发现终态一定是 \([2,n-2]\) 中的每个点都与 \(n\) 连边. 关于凸多边形的划分问题,可以将它看作一棵二叉树:每个树点可以看做点可以看做边. 本题中看做点来处理 ...
- [HNOI2019]多边形
Luogu5288 注意:n边形里共有n-3条边 最优步数=不与n相连的边数,关键是方案数. 按照处理顺序可以转化为树形结构即二叉树森林,转移方案数用组合数即可 关键是快速处理修改. 1.最优解减少一 ...
- 【题解】Luogu P5288 [HNOI2019]多边形
原题传送门 HN的题目就是毒瘤 我们有以下猜想: 1.最后所有的线都连到了n号点上 2.最小步数应该为n-3-已经连到n号点的线段数量 本来有些边\((a_i,n)\)会将整个图分割成很多个区间.对于 ...
- ZJOI2019Day2余姚中学游记(4.23~4.26)
前言 \(Day2\),又是一场噩梦. 前段时间去做了挺多十二省联考和\(HNOI2019\)的题目,还订正掉了\(Day1\)的\(T1\)和\(T2\)(\(T3\)动态\(DP\)完全不想订正啊 ...
- Loj #3056. 「HNOI2019」多边形
Loj #3056. 「HNOI2019」多边形 小 R 与小 W 在玩游戏. 他们有一个边数为 \(n\) 的凸多边形,其顶点沿逆时针方向标号依次为 \(1,2,3, \ldots , n\).最开 ...
随机推荐
- linux监控文件夹内的文件数量
开发的时候遇到一个问题,服务器一旦重启,项目生成的文件就丢失了,感觉很莫名其妙..一开始猜测是文件流没有关闭,检查了代码,感觉没毛病.于是先看看是关机丢失了文件还是开机被删除了.下面的脚本每秒执行一次 ...
- Http指南(1)
网关:是一种特殊的服务器,作为其他服务器的中间实体使用; Agent代理:所有发布web请求的应用程序都是HTTP Agent代理.Web浏览器其实就是一种代理; HTTP报文是在HTTP应用程序之间 ...
- 5分钟入门自动化测试——你应该学会的Postman用法(2)
前言 之前的一篇文章<你应该学会的Postman用法>,主要介绍了postman的一些高级的用法,便于日常开发和调试使用,本文的基础是对postman的基本使用以及一些高级用法有一定的了解 ...
- 写入mssql出现乱码
1.出现乱码的场景如下: --------------------------------------------------------------------------------------- ...
- MySQL高可用架构-MMM环境部署记录
MMM介绍MMM(Master-Master replication manager for MySQL)是一套支持双主故障切换和双主日常管理的脚本程序.MMM使用Perl语言开发,主要用来监控和管理 ...
- 腾讯QQ的商业模式
近期听到许多关于腾讯QQ的报道,然后想到之前自己在QQ上遇到的一些问题,一瞬间感觉大脑的所有想法喷涌而出. 以前总觉得QQ是个很好的平台,我们可以通过QQ和自己的亲人朋友爱人聊天,有时候还可以在自己的 ...
- 《Gogoing》Alpha版会议总结
一.开会的过程 首先大家对自己的任务进行了汇报,然后大家就当前最需要解决的问题提出解决方案,最后相互鼓励,相互帮助,探讨下一步该怎么做. 二.讨论的问题 百度地图API代码和界面代码为什么对接不上? ...
- Jquery画折线图、柱状图、饼图
1.今天做了一个折线图,首先需要导js文件.这里有一个demo:http://files.cnblogs.com/files/feifeishi/jquery_zhexiantubingtuzhuzh ...
- IT行业创新的读后感
一.什么是创新 创新是以新思维.新发明和新描述为特征的一种概念化过程.它原意有三层含义,第一,更新:第二,创造新的东西:第三,改变.创新是人类特有的认识能力和实践能力,是人类主观能动性的高级表现形式, ...
- Android Studio下创建menu布局文件
一.问题: android studio项目中没有看到menu文件夹: 在android studio项目中想要添加menu布局文件,一开始我的做法是:直接在res文件夹右键选择xml文件来添加,如下 ...