【线段树】【数列】【贪心】【倍增】CF992E Nastya and King-Shamans 题解

 

   利用了数据增长幅度的一道题,复杂度和\(a_i\)有很大关系。

 

Description

 

Nastya likes reading and even spends whole days in a library sometimes. Today she found a chronicle of Byteland in the library, and it stated that there lived shamans long time ago. It is known that at every moment there was exactly one shaman in Byteland, and there were \(n\) shamans in total enumerated with integers from \(1\) to \(n\) in the order they lived. Also, each shaman had a magic power which can now be expressed as an integer.

 

The chronicle includes a list of powers of the \(n\) shamans. Also, some shamans can be king-shamans, if they gathered all the power of their predecessors, i.e. their power is exactly the sum of powers of all previous shamans. Nastya is interested in whether there was at least one king-shaman in Byteland.

 

Unfortunately many of the powers are unreadable in the list, so Nastya is doing the following:

  • Initially she supposes some power for each shaman.
  • After that she changes the power of some shaman \(q\) times (the shamans can differ) and after that wants to check if there is at least one king-shaman in the list. If yes, she wants to know the index of any king-shaman.

 

Unfortunately the list is too large and Nastya wants you to help her.

 

Input

The first line contains two integers \(n\) and \(q(1\le n,q\le 2\cdot 10^5)\).

 

The second line contains \(n\) integers \(a_1,\dots , a_n (0\le a_i\le 10^9)\), where \(a_i\) is the magic power of the \(i\)-th shaman.

 

After that \(q\) lines follow, the \(i\)-th of them contains two integers \(p_i\) and \(x_i (1\le p_i\le n, 0\le x_i\le 10^9)\) that mean that the new power of the \(p_i\)-th shaman is \(x_i\).

 

Output

Print \(q\) lines, the \(i\)-th of them should contain \(-1\), if after the \(i\)-th change there are no shaman-kings, and otherwise a single integer \(j\), where \(j\) is an index of some king-shaman after the \(i\)-th change.

 

If there are multiple king-shamans after each change, print the index of any of them.

 

Examples

input
2 1
1 3
1 2
output
-1
input
3 4
2 2 3
1 1
1 2
2 4
3 6
output
3
2
-1
3
input
10 7
0 3 1 4 6 2 7 8 10 1
2 5
1 3
9 36
4 10
4 9
1 2
1 0
output
1
-1
9
-1
4
-1
1

Note

In the first example powers of shamans after the first change are equal to \((2, 3)\). The answer equals  \(-1\), because the sum of powers of shamans before the first shaman is equal to \(0\), and before the second is equal to \(2\).

 

In the second example after the first change the powers are equal to \((1, 2, 3)\). The answer is equal to \(3\), because the power of the third shaman is equal to \(3\), and the sum of powers of the first and the second shaman is also \(1+2=3\). After the second change the powers become equal to \((2, 2, 3)\), where the answer equals \(2\). After the third change the powers become equal to \((2, 4, 3)\), where the answer equals  \(-1\). After the fourth change the powers become equal to \((2, 4, 6)\), where the answer equals \(3\).

 

题意:

   给定\(n\)个数构成的一个数列,给出\(q\)次操作,每次操作进行单点修改。问每次修改后是否\(\exists i\in[1,n]\)满足\(S_{i-1}=a_i,S\)是前缀和,如果有,输出任意一个,否则输出\(-1\)。

 

题解:

   这个题暴力判断的话是需要\(O(nq)\)的,用线段树维护是\(O(q\log n)\),总体上看都会T。而且线段树无法动态维护有负数的区间中是否出现了\(0\),因此我们需要换成线段树能维护的信息来转移。

 

   考虑满足条件的位置是\(a_i=S_{i-1}\)。可知一旦满足这个条件,\(a_i\)就会至少增大到\(a_{i-1}\)的两倍。而我们反过来思考,如果\(a_i\)能增大到\(a_{i-1}\)的两倍,那么\(S_{i-1}-a_i\le 0\)。此时可以发现,满足\(S_{i-1}-a_i\le 0\)的位置,至多只有\(\log a_i\)个,因为每相邻两个之间的商都大于\(2\)。而这里的\(S_{i-1}-a_i\)是可以用线段树维护并实时更新最小值的,我们只需要查询最小值是否小于0就能知道是否可能存在一个\(S_{i-1}-a_i=0\)。

 

   这个题一开始以为是用差分做,没想到有这样一个类似“倍增”的性质,完美降低了复杂度。但是这个方面也是比较难想的,不仅是想到这个性质并用在复杂度上,而且要跳出自己错误的思想圈。总时间复杂度为\(O(q\log n\log a_i)\)。

 

Code:

#include<cstdio>
#include<cstring>
#define inf 1000000000
#define ls (k<<1)
#define rs (k<<1|1)
#define mid (l+r>>1)
#define Mid (t[k].l+t[k].r>>1)
long long Min(long long x,long long y)
{
    return x<y?x:y;
}
struct node
{
    int l,r;
    long long v,lazy;
    node(int l,int r)
    {
        this->l=l;
        this->r=r;
        lazy=0;
    }
    node(){}
}t[800001];
long long sum[200100],a[200100];
void build(int k,int l,int r)
{
    t[k]=node(l,r);
    if(l==r)
    {
        t[k].v=sum[l-1]-a[l];
        return;
    }
    build(ls,l,mid);
    build(rs,mid+1,r);
    t[k].v=Min(t[ls].v,t[rs].v);
}
void pushdown(int k)
{
    if(t[k].l==t[k].r||t[k].lazy==0)
        return;
    long long x=t[k].lazy;
    t[k].lazy=0;
    t[ls].lazy+=x;
    t[ls].v+=x;
    t[rs].lazy+=x;
    t[rs].v+=x;
}
void change(int k,int l,int r,long long x)
{
    if(t[k].l==l&&t[k].r==r)
    {
        t[k].v+=x;
        t[k].lazy+=x;
        return;
    }
    pushdown(k);
    if(r<=Mid)
        change(ls,l,r,x);
    else if(l>Mid)
        change(rs,l,r,x);
    else
    {
        change(ls,l,Mid,x);
        change(rs,Mid+1,r,x);
    }
    t[k].v=Min(t[ls].v,t[rs].v);
    return;
}
int ask(int k,int l,int r)//返回区间内最左边一个<=0的位置
{
    pushdown(k);
    if(t[k].v>0||l>r)
        return inf;
    if(t[k].l==t[k].r)
        return t[k].l;
    if(r<=Mid)
        return ask(ls,l,r);
    else if(l>Mid)
        return ask(rs,l,r);
    else
    {
        int tmp=ask(ls,l,Mid);
        return tmp==inf?ask(rs,Mid+1,r):tmp;
    }
}
bool check(int k,int p)
{
    pushdown(k);
    if(t[k].l==t[k].r)
        return t[k].v==0;
    if(p<=Mid)
        return check(ls,p);
    return check(rs,p);
}
int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-')
            f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
int main()
{
    int n,m,u,v,flag;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;++i)
    {
        a[i]=read();
        sum[i]=sum[i-1]+a[i];
    }
    build(1,1,n);
    for(int i=1;i<=m;++i)
    {
        flag=0;
        u=read();
        v=read();
        int d=v-a[u];
        if(u<n)
            change(1,u+1,n,d);
        change(1,u,u,a[u]-v);
        a[u]=v;
        int t=ask(1,1,n);
        while(t<=n)
        {
            if(check(1,t))
            {
                printf("%d\n",t);
                flag=1;
                break;
            }
            t=ask(1,t+1,n);
        }
        if(!flag)
            puts("-1");
    }
    return 0;
}