思路:大模拟
- 我们只需要对所有操作1确认它至少x米可以上top,至多y米必定上top来确认是否使用,只要每次操作1对于当前区间[l,r](上top区间)有x<=r&&y>=l,那么可以采纳,并且更新l,r。否则不用
- 对于操作2,我们只需判断在最少米与最高米上top天数是否相同,是则采纳,否则-1
- 判断天数ans是否相同(以l为例),有
。向上取整,所以我们给分子加上分母-1(即a-b-1),所以得到![ans=\frac{l-b+a-b-1}{a-b}](https://latex.csdn.net/eq?ans%3D%5Cfrac%7Bl-b+a-b-1%7D%7Ba-b%7D)
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define endl "\n"
#define int ll
int32_t main()
{
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t,q,op,a,b,n,x,y;
cin>>t;
while (t--)
{
cin>>q;
int l=1,r=1e18;
while (q--)
{
cin>>op>>a>>b;
if (op==1)
{
cin>>n;
if (n==1)
{
x=1,y=a;
}
else
{
x=1+a*(n-1)-b*(n-2);
y=(a-b)*(n-1)+a;
}
if (y>=l&&x<=r)//判断是否采用,是则更新区间,尽量缩小它
{
cout<<1<<" ";
l=max(l,x),r=min(r,y);
}
else cout<<0<<" ";
}
else
{
x=a>=l?1LL:(l-b+a-b-1)/(a-b);
y=a>=r?1LL:(r-b+a-b-1)/(a-b);
if (x==y)cout<<x<<" ";
else cout<<-1<<" ";
}
}
cout<<endl;
}
system("pause");
return 0;
}
思路:并查集
- 如果有解,必然存在从一个u(a[u]=0),可以走过所有点。
- 我们可以走所有a[i]=0的点(前提是它没有被别人来过),然后记录这个点可以走过的所有点(把这些点都归为当前i这个集合,并且存储这个集合的点数)
- 我们每次走时,如果遇到集合u(或者点),并且我x(从x出发)当前消灭怪物数,那么我把这个集合吸收。
- 遍历完后,如果有一个点可以吸收所有点,有解
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define endl "\n"
typedef pair<long long, long long> pll;
const int N = 2e5 + 10;
int a[N],fa[N],cnt[N];
int vis[N];
struct node
{
int next,to;
} edge[N<<1];
int head[N],num;
int t,n,m;
inline void init()
{
for (int i=0; i<=n; ++i)head[i]=0,fa[i]=i,cnt[i]=1,vis[i]=0;
num=0;
}
inline void add(int u,int v)
{
edge[++num].next=head[u];
edge[num].to=v;
head[u]=num;
}
inline int find(int u)//并查集找祖先
{
if (u!=fa[u])fa[u]=find(fa[u]);
return fa[u];
}
bool check(int x)//检查从x出发是否可以经过所有点
{
set<pll>s;//用set存储,每次取a[i]最小的点出来
s.insert({a[x],x});
while (!s.empty())
{
int u=(*s.begin()).second;
s.erase(s.begin());
if (a[u]>cnt[x])return (cnt[x]==n);//如果这个点到不了,后面都到不了,直接返回
int tmp=find(u);
if (tmp!=x)fa[tmp]=x,cnt[x]+=cnt[tmp],cnt[tmp]=0;//如果这个点的祖先不是x,吸收这个祖先的集合
for (int i=head[u]; i; i=edge[i].next)
{
int v=edge[i].to;
if (vis[v]<x)//vis两个功能,1个是判断a[i]=0的点有没有被访问过,有则main函数不用来了,而是一个check(x)回合避免多次访问一个点v
vis[v]=x,s.insert({a[v],v});
}
}
return (cnt[x]==n);
}
int32_t main()
{
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin>>t;
while (t--)
{
cin>>n>>m;
init();
for (int i=1; i<=n; ++i)cin>>a[i];
int x,y;
for (int i=1; i<=m; ++i)
{
cin>>x>>y;
add(x,y),add(y,x);
}
bool flag=0;
for (int i=1; i<=n; ++i)if (a[i]==0&&!vis[i])if (check(i))
{
cout<<"YES"<<endl;
flag=1;
break;
}
if (!flag)
cout<<"NO"<<endl;
}
system("pause");
return 0;
}