刷题 链表 优先队列

发布时间 2024-01-09 22:30:00作者: modemingzi

2024.1.9 cf Hello 2024 1919D

 

解题思路

 

  这题理解一下就是,找出数组中每一个比左数或右数大1的数,从大到小(体现优先队列)删除(体现链表),对访问过的数打个标记(vis),最后数组里的数要么被打过标记,要么是0.

 

代码

 

 

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=200005;
int a[N],L[N],R[N],vis[N];
int main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(nullptr);
	int t;
	cin>>t;
	while(t--)
	{
		int n;
		priority_queue<pair<int,int>> pq;
		cin>>n;
		for(int i=1;i<=n;i++)
		{
			cin>>a[i];
			vis[i]=0;
		}
		for(int i=1;i<=n;i++)
		{
			if(i>1&&a[i]-1==a[i-1]&&!vis[i])
			{
				pq.push({a[i],i});
				vis[i]=1;//打标记
			}
			if(i<n&&a[i]-1==a[i+1]&&!vis[i])
			{
				pq.push({a[i],i});
				vis[i]=1;
			}
		}
		R[0]=1,L[n+1]=n;
		vis[0]=vis[n+1]=1;
		for(int i=1;i<=n;i++)//数组模拟链表,L是前一个结点,R是后一个结点
		{
			L[i]=i-1;
			R[i]=i+1;
		}
		for(int i=1;i<=n;i++)
		{
			if(pq.empty())break;
			auto u=pq.top().second;//取出顶上的最大元素,从大到小删
			int x=L[u],y=R[u];
			if(x&&a[x]==a[u]-1||y!=n+1&&a[y]==a[u]-1)
			{
				pq.pop();
				R[x]=y,L[y]=x;//删除结点(O(1)的复杂度)
				vis[u]=1;
				if(x&&y!=n+1)
				{
					if(a[y]==a[x]-1&&!vis[x])
					{
						pq.push({a[x],x});
						vis[x]=1;
					}
					if(a[x]==a[y]-1&&!vis[y])
					{
						pq.push({a[y],y});
						vis[y]=1;
					}
				}
			}
		}
		bool ok=1;
		int cnt=0;
		for(int i=1;i<=n;i++)
		{
			if(a[i]&&!vis[i])ok=0;//数组里的数要么被标记过,要么是0
			if(!a[i])cnt++;//0只能有一个
		}
		if(ok&&cnt==1)
		{
			cout<<"YES\n";
		}
		else cout<<"NO\n";
	}
	return 0;
}