正题
题目链接:https://www.luogu.com.cn/problem/P7078
题目大意
有nnn条贪吃蛇,第iii条长度为aia_iai,每次最长的那条蛇可以选择吃掉最短的那条蛇,然后自己的长度减去其长度,也可以不吃然后结束游戏。
现在询问在所有蛇都希望吃的蛇最多且自己不会被吃的情况下最后会留下多少条蛇。
TTT次每次修改kkk个值,保证修改前后aaa单调不降。
3≤n≤106,1≤T≤10,0≤k≤1053\leq n\leq 10^6,1\leq T\leq 10,0\leq k\leq 10^53≤n≤106,1≤T≤10,0≤k≤105
解题思路
考虑一条蛇什么时候会选择不吃。
首先如果一条蛇吃掉别的蛇之后它不是最小的蛇,那么它一定会去吃这条蛇。假设最大的和次大的蛇长度为a,ba,ba,b,最小和次小的为c,dc,dc,d,由于a−c>da-c>da−c>d又有b−d<a−cb-d<a-cb−d<a−c那么显然如果bbb蛇吃了肯定会比aaa蛇先死,那么如果bbb会死那么它肯定不吃ddd那么aaa蛇显然也不会被吃。
如果一条蛇吃了别的蛇后它是最小的蛇会发生什么。记蛇从大到小排序为a,b,c,...a,b,c,...a,b,c,...,那么如果蛇aaa吃了最小的后它成最小的了且bbb会吃,那么aaa肯定不吃。此时我们就需要判断bbb是否吃了,同理的,如果bbb吃了最小的之后它也是最小的那么就需要考虑ccc吃不吃最小的。
此时递归下去直到一条吃了之后不是最小的或者只剩两条蛇时就结束了。
然后用类似于合并果子那样的方法用两个队列维护即可。
时间复杂度:O(Tn)O(Tn)O(Tn)
code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
using namespace std;
const int N=1e6+10;
int T,n,a[N],w[N],q1[N],q2[N];
int read(){int x=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-')f=-f;c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}
bool cmp(int x,int y)
{return (w[x]==w[y])?x<y:w[x]<w[y];}
void solve(){int h1=1,t1=n,h2=1,t2=0,v,p;T--;for(int i=1;i<=n;i++)w[q1[n-i+1]=i]=a[i];while(1){if(t1-h1+1+t2-h2+1==2){printf("%d\n",1);return;}if(t2-h2+1<=0||t1-h1+1>0&&cmp(q2[h2],q1[h1])){v=w[p=q1[h1]];p=q1[h1];h1++;if(t2-h2+1<=0||t1-h1+1>0&&cmp(q1[t1],q2[t2]))v-=w[q1[t1]],t1--;else v-=w[q2[t2]],t2--;}else{v=w[p=q2[h2]];h2++;if(t2-h2+1<=0||t1-h1+1>0&&cmp(q1[t1],q2[t2]))v-=w[q1[t1]],t1--;else v-=w[q2[t2]],t2--;}w[p]=v;if((t2-h2+1<=0||cmp(p,q2[t2]))&&(t1-h1+1<=0||cmp(p,q1[t1]))){q2[++t2]=p;break;}q2[++t2]=p;}int cnt=0,f=t2-h2+1+t1-h1+1;while(1){cnt++;if(t1-h1+1+t2-h2+1==2){printf("%d\n",f+(cnt&1));return;}if(t2-h2+1<=0||t1-h1+1>0&&cmp(q2[h2],q1[h1])){v=w[p=q1[h1]];p=q1[h1];h1++;if(t2-h2+1<=0||t1-h1+1>0&&cmp(q1[t1],q2[t2]))v-=w[q1[t1]],t1--;else v-=w[q2[t2]],t2--;}else{v=w[p=q2[h2]];h2++;if(t2-h2+1<=0||t1-h1+1>0&&cmp(q1[t1],q2[t2]))v-=w[q1[t1]],t1--;else v-=w[q2[t2]],t2--;}w[p]=v;if((t2-h2+1<=0||cmp(p,q2[t2]))&&(t1-h1+1<=0||cmp(p,q1[t1]))){q2[++t2]=p;continue;}printf("%d\n",f+(cnt&1));return;}return;
}
int main()
{T=read();n=read();for(int i=1;i<=n;i++)a[i]=read();solve();while(T){int k=read();while(k--){int x=read(),w=read();a[x]=w;}solve();}return 0;
}