[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 cnt2cnt4cnt3cnt1
但显然,它们两个不能同时取等,因为我们最后一次合并后肯定还会剩一个。
所以,我们真正的必要条件是: ( 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) (cnt2cnt4cnt3>cnt1)(cnt2>cnt4cnt3cnt1)
容易发现这个条件也是充分的,因为按照我们上面的方法是可以构造得到解的。

所以,只需要按我们上面的方法缩点后判断一下即可。
时间复杂度 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的主要内容,如果未能解决你的问题,请参考以下文章

[AGC058C]Planar Tree

AGC018D - Tree and Hamilton Path

AtCoder Grand Contest 014 E:Blue and Red Tree

AtCoder AGC030B Tree Burning

[AGC017D]Game on Tree

AGC 030 B - Tree Burning