【JZOJ A组】挑战

版权声明:转载者乖乖♂站好 https://blog.csdn.net/Eric1561759334/article/details/82719112

Description

这里写图片描述

Input

这里写图片描述

Output

这里写图片描述

Sample 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

Sample Output

1
-1
9
-1
4
-1
1

Data Constraint

这里写图片描述

思路

数据结构毒瘤题

题意是1~n个非负整数有m次修改,每次修改后求出一个最小的位置t,使得sum[1~t-1]=p[t]。

假设当前修改的位置x在上次得出的答案位置的后面,那么答案不变,对吧?
那么假设位置x在上次得出的答案位置的前面,这次的答案就要重新计算了。 此时这次答案若存在,则一定在x~n范围内。

我们在x~n范围内找到一个最靠前的位置t,使得t上面的值要大于等于sum[1~x-1]。因为如果t要是史前最大毒瘤,则p[t]是要等于sum[1~t-1],所以p[t]一定要满足大于等于sum[1~x-1]。(这里之所以有等于是因为t有可能就在位置x)

找到了t以后,我们判断t是否是史前最大毒瘤(即t是否等于sum[1~t-1]),如果是,就是答案了,如果不是,则答案区间变成了t+1~n,我们再找下一个t‘

t’要满足大于sum[1~t]的且最靠前的。(之所以不让t’一次性就大于等于sum[1~t’-1]是因为这样真的做不到)

然后我们把找出的t’判断是否是答案,如果是就输出,如果不是就继续找下一个t”,以此类推。

算一下时间复杂度。

每次找t可以用logn(我不会,想知道的可以去问问其他过的dalao)或者logn^2的时间(二分套线段树)。

至于有多少个t嘛,最多只可能有log(10^9)个,为什么呢?因为是类似前缀和的,所以每个sum[1~t]相当于至少是前面sum[1~t-1]的2倍。至于p有0的情况嘛,讲题的时候我被一群dalao带偏了,其实现在想想有很多0也没关系啊,t肯定不会在0上,那不是直接跳过的吗。 如果全部都是0,那答案是1直接稍微判断一下使t不会一个一个往下枚举就好了。

所以,综上,时间复杂度是O(能过)呸应该是O(mlog^2)。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=2e6+777;
int tr[maxn],a[maxn],n,m,ans;
int lowbit(int x)
{
    return x&-x;
}
void ins(int x,int t)
{
    for(int i=x; i<=n; i+=lowbit(i)) tr[i]+=t;
}
int query(int x)
{
    int r=0;
    for(int i=x; i; i-=lowbit(i)) r+=tr[i];
    return r;
}
void print(int x)
{
    if(x>n) printf("-1\n");else printf("%d\n",x);
}
int fin(int x)
{
    int s=n+1,l=x+1,r=n,mx=query(x);
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(query(mid)>=mx*2) r=mid-1,s=mid;else l=mid+1;
    }
    return s;
}
int main()
{
    freopen("challenge.in","r",stdin); freopen("challenge.out","w",stdout);
    scanf("%d%d",&n,&m);
    ans=n+1;
    int sum=0;
    for(int i=1; i<=n; i++)
    {
        scanf("%d",&a[i]);
        ins(i,a[i]);
        if(a[i]==sum) ans=min(ans,i);
        sum+=a[i];
    }
    for (int i=1;i<=m;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        ins(x,y-a[x]),a[x]=y;
        if (x>ans) printf("%d\n",ans);
        else 
        {
            ans=n+1;
            if (query(x)==query(x-1)*2) ans=x;
            else
            {
                while(x<=n)
                {
                    int y=fin(x);
                    if (y==0) break;
                    if (query(y)==query(y-1)*2)
                    {
                        ans=y;
                        break;
                    }
                    x=y;
                }
            }
            if (ans==n+1) printf("-1\n"); else printf("%d\n",ans);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/Eric1561759334/article/details/82719112
今日推荐