題目描述
題解
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\n",ans);
}
fclose(stdin);
fclose(stdout);
return 0;
}