[AGC058C]Planar Tree
Posted StaroForgin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[AGC058C]Planar Tree相关的知识,希望对你有一定的参考价值。
Planar Tree
题解
首先,我们看这题呀,感觉这东西好像很阴间的样子,想想有没有什么比较好的方法。
好像没有的样子。
首先当然可以有比较简单的
O
(
n
3
)
O\\left(n^3\\right)
O(n3)的区间
d
p
dp
dp做法,不过这东西好像根本没有利用上我们
A
i
∈
[
1
,
4
]
A_i\\in[1,4]
Ai∈[1,4]的性质。
不妨考虑一下这个性质有什么用。
显然,这里我们可以发现,
A
i
=
1
/
4
A_i=1/4
Ai=1/4的点连接到的点的权值都是唯一的,它们如果与
2
/
3
2/3
2/3相邻,显然可以直接合并到那上面。
同样,如果有两个相邻的权值相同的数,也是可以合并到一起的,因为它们必然可以连向相同的目标。
我们可以把上面两类点给合并起来,得到一个相邻的点都不同并且不存在
(
1
,
2
)
/
(
3
,
4
)
(1,2)/(3,4)
(1,2)/(3,4)相邻的图形。
但这又有什么用呢?
我们可以发现,我们的树其实是可以由不断合并在环上相邻的边构成的。
显然,对于一个大小为
n
n
n的环,其生成树上肯定会存在一个叶子与其父亲相邻,否则必然会出现相交的线段。
也就是说,我们可以由这种方式递归构造出整棵树。
我们上面的合并显然是优秀的合并,也就是说,它并不会影响最后的答案是否有解。
那么我们再来看在我们的新环上有能怎么办了?
如果这个环仅存在
2
2
2和
3
3
3的时候显然是有解的,所以我们的目的是将这个环上的
1
,
4
1,4
1,4全部去掉。
如果要去掉
1
1
1,环上肯定得存在
2
2
2,为了两者不相邻,它们肯定会用
3
3
3隔开,也是说能合并的地方必然长这个样子:
.
.
.
,
1
,
3
,
1
,
3
,
1
,
3
,
1
,
3
,
2
,
.
.
.
...,1,3,1,3,1,3,1,3,2,...
...,1,3,1,3,1,3,1,3,2,...,这样我合并
(
1
,
2
)
(1,2)
(1,2)后必然会去掉一个
3
3
3。
同样,在合并
(
3
,
4
)
(3,4)
(3,4)后也必然去掉一个
2
2
2。
也就是说,我们有解的必要条件是
c
n
t
2
⩾
c
n
t
4
∧
c
n
t
3
⩾
c
n
t
1
cnt_2\\geqslant cnt_4\\wedge cnt_3\\geqslant cnt_1
cnt2⩾cnt4∧cnt3⩾cnt1。
但显然,它们两个不能同时取等,因为我们最后一次合并后肯定还会剩一个。
所以,我们真正的必要条件是:
(
c
n
t
2
⩾
c
n
t
4
∧
c
n
t
3
>
c
n
t
1
)
∨
(
c
n
t
2
>
c
n
t
4
∧
c
n
t
3
⩾
c
n
t
1
)
(cnt_2\\geqslant cnt_4\\wedge cnt_3>cnt_1)\\vee(cnt_2>cnt_4\\wedge cnt_3\\geqslant cnt_1)
(cnt2⩾cnt4∧cnt3>cnt1)∨(cnt2>cnt4∧cnt3⩾cnt1)。
容易发现这个条件也是充分的,因为按照我们上面的方法是可以构造得到解的。
所以,只需要按我们上面的方法缩点后判断一下即可。
时间复杂度
O
(
∑
n
)
O\\left(\\sum n\\right)
O(∑n)。
源码
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int,int> pii;
#define MAXN 300005
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
const int INF=0x3f3f3f3f;
const int mo=998244353;
template<typename _T>
void read(_T &x)
_T f=1;x=0;char s=getchar();
while(s<'0'||s>'9')if(s=='-')f=-1;s=getchar();
while('0'<=s&&s<='9')x=(x<<3)+(x<<1)+(s^48);s=getchar();
x*=f;
template<typename _T>
_T Fabs(_T x)return x<0?-x:x;
int add(int x,int y,int p)return x+y<p?x+y:x+y-p;
void Add(int &x,int y,int p)x=add(x,y,p);
int qkpow(int a,int s,int p)int t=1;while(s)if(s&1)t=1ll*a*t%p;a=1ll*a*a%p;s>>=1;return t;
int T,n,a[MAXN],b[MAXN],head,tail,cnt[5];
int main()
read(T);
while(T--)
read(n);head=tail=0;
for(int i=1;i<=n;i++)
read(a[i]);a[i]--;bool flag=0;
while(head<tail)
if(b[tail-1]==a[i])tail--;continue;
if((b[tail-1]^a[i])==1)
if(a[i]==0||a[i]==3)flag=1;
elsetail--;continue;
break;
if(!flag)b[tail++]=a[i];
while(head+1<tail)
if(b[head]==b[tail-1])tail--;
else if((b[head]^b[tail-1])==1)
if(b[head]==0||b[head]==3)head++;
else tail--;
else break;
for(int i=head;i<tail;i++)cnt[b[i]]++;
if(cnt[0]>cnt[2]||cnt[3]>cnt[1])puts("No");
else if(cnt[0]==cnt[2]&&cnt[3]==cnt[1])puts("No");
else puts("Yes");
cnt[0]=cnt[1]=cnt[2]=cnt[3]=0;
return 0;
谢谢!!!
以上是关于[AGC058C]Planar Tree的主要内容,如果未能解决你的问题,请参考以下文章
AGC018D - Tree and Hamilton Path