题目描述
题解
70分没想清楚+时间不够=20分
考场上的奇妙做法:
假设每条蛇都没有脑子,不管自己的死活往下吃,那么最后会形成一棵操作树,(u,v,t)表示u在t时间吃了v
显然根不会被吃,所以其相连的有危险,所以它们会放掉自己儿子中时间最大的那个,设其为y父亲为x,则非x外的蛇知道y是最大的,所以如果它们不放的话x必须要放,x也知道别的蛇不会放,所以它也会放了y,并且这样对所有有危险的蛇都是最优的
然后有一部分蛇会脱离危险,所以它们可以继续往下吃,如此用前缀和优化一下随便维护即可做到O(n)
问题是怎么O(n)求出操作树,具体见https://blog.csdn.net/EI_Captain/article/details/109552980
换一种做法(Orz lk),如果一条蛇吃完后不会变成最小的则它一定会吃,因为下一条蛇吃了之后会比自己更小,死得比自己快,所以把锅丢给它
如果变成最小的,那么往后找出按照这样吃第一条不会变成最小的蛇,那么它一定会吃,下一条一定不吃,下下条一定会吃,按照奇偶性讨论
用两个队列即可维护,只要没有出现变成最小的话那么max递减min递增,相减得到的递减丢到第二个队列里
如果变成最小的,那么每次只能跑到末尾否则就停
时间复杂度O(n)
code
#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define ll long long
#define file
using namespace std;
struct type{int s,x;} s1,s2;
struct Queue{type d[1000001];int h,t;
void push(type s) {d[++t]=s;}
void pop(bool tp) {if (!tp) ++h; else --t;}
void clear() {h=1,t=0;}
bool empty() {return h>t;}
type head() {return d[h];}
type tail() {return d[t];}
} q[2];
int a[1000001],T,n,i,j,k,l,I,x,y,ans,I1,I2,sum;
bool operator < (type a,type b) {return a.s<b.s || a.s==b.s && a.x<b.x;}
bool operator > (type a,type b) {return a.s>b.s || a.s==b.s && a.x>b.x;}
void swap(int &x,int &y) {int z=x;x=y;y=z;}
int main()
{
// freopen("snakes.in","r",stdin);
// #ifdef file
// freopen("snakes.out","w",stdout);
// freopen("b.out","w",stdout);
// #endif
scanf("%d",&T);
fo(I,1,T)
{
if (I==1)
{
scanf("%d",&n);
fo(i,1,n) scanf("%d",&a[i]);
}
else
{
scanf("%d",&k);
fo(i,1,k) scanf("%d%d",&x,&y),a[x]=y;
}
q[0].clear(),q[1].clear(),ans=n;
I1=0,I2=1;
fd(i,n,1) q[I1].push(type{a[i],i});
while (ans>1)
{
--ans;
if (q[I2].empty() || q[I1].tail()<q[I2].tail()) s2=q[I1].tail(),q[I1].pop(1); else s2=q[I2].tail(),q[I2].pop(1);
if (!s2.s) continue;
if (q[I2].empty() || q[I1].head()>q[I2].head()) s1=q[I1].head(),q[I1].pop(0); else s1=q[I2].head(),q[I2].pop(0);
s1.s-=s2.s;
if (q[I1].empty()) swap(I1,I2);
q[I2].push(s1);
if (q[I1].tail()>s1) break;
}
if (ans>1)
{
sum=0;
while (sum<ans-1)
{
if (q[I2].empty() || q[I1].tail()<q[I2].tail()) s2=q[I1].tail(),q[I1].pop(1); else s2=q[I2].tail(),q[I2].pop(1);
if (q[I2].empty() || q[I1].head()>q[I2].head()) s1=q[I1].head(),q[I1].pop(0); else s1=q[I2].head(),q[I2].pop(0);
s1.s-=s2.s;
if (q[I1].empty()) swap(I1,I2);
if (!q[I1].empty() && q[I1].tail()<s1 || !q[I2].empty() && q[I2].tail()<s1) break;
q[I2].push(s1);
++sum;
}
sum+=sum==(ans-1);
ans+=!(sum&1);
}
printf("%d
",ans);
}
fclose(stdin);
fclose(stdout);
return 0;
}