zoukankan      html  css  js  c++  java
  • CodeForces992E 二分 + 树状数组(线段树)

    http://codeforces.com/problemset/problem/992/E

    题意:给定一个序列 ai ,记其前缀和序列为 si ,有 q 个询问,每次单点修改,询问是否存在一个 i 满足 ai=si1,有多解输出任意一个,无解输出 -1

    思路一:构造一个b[i] = a[i] - s[i - 1]的序列,答案就是在其中寻找为0的位置,对每一次操作进行一个线段树的单点修改和区间修改之后对一整个区间寻找是否存在0的位置,但是最坏的情况下能达到N * Q * lnN,虽然据说可过但是觉得并不靠谱

    思路2:ai = si - 1,考虑转化一下就变成了si = 2 * s(i - 1),所以对于起始位置x,下一个可能符合答案ans - 1的位置的就是最大的sk < 2 * sx,因为x到k中间的位置很显然前一个数的s会比sx大,后一个数的位置会比sk小,很显然并不满足。

    所以可以考虑用树状数组维护前缀和之后用一个类似跳的算法加一个二分寻找ans,时间复杂度是QlnNlnNlnN,有点慢但依然可以过。

    #include <map>
    #include <set>
    #include <ctime>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <string>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <sstream>
    #include <iostream>
    #include <algorithm>
    #include <functional>
    using namespace std;
    inline int read(){int now=0;register char c=getchar();for(;!isdigit(c);c=getchar());
    for(;isdigit(c);now=now*10+c-'0',c=getchar());return now;}
    #define For(i, x, y) for(int i=x;i<=y;i++)  
    #define _For(i, x, y) for(int i=x;i>=y;i--)
    #define Mem(f, x) memset(f,x,sizeof(f))  
    #define Sca(x) scanf("%d", &x)
    #define Sca2(x,y) scanf("%d%d",&x,&y)
    #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
    #define Scl(x) scanf("%lld",&x);  
    #define Pri(x) printf("%d
    ", x)
    #define Prl(x) printf("%lld
    ",x);  
    #define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
    #define LL long long
    #define ULL unsigned long long  
    #define mp make_pair
    #define PII pair<int,int>
    #define PIL pair<int,long long>
    #define PLL pair<long long,long long>
    #define pb push_back
    #define fi first
    #define se second 
    typedef vector<int> VI;
    const double eps = 1e-9;
    const int maxn = 2e5 + 10;
    const int maxm = 1e6 + 10;
    const int INF = 0x3f3f3f3f;
    const int mod = 1e9 + 7; 
    int N,Q;
    LL a[maxn];
    LL tree[maxn];
    void add(int x,int t){for(;x <= N ; x += x & -x) tree[x] += t;}
    LL getsum(int x){LL ans = 0; for(;x > 0 ; x -= x & -x) ans += tree[x]; return ans;}
    void solve(){
        if(a[1] == 0) return (void)puts("1");
        int x = 1;
        while(x < N){
            LL sum = getsum(x) * 2;
            if(getsum(x + 1) == sum) return (void)printf("%d
    ",x + 1);
            int ans = x,l = x + 1,r = N;
            while(l <= r){
                int m = (l + r) >> 1;
                if(getsum(m) < sum){
                    ans = m;
                    l = m + 1;
                }else{
                    r = m - 1;
                }
            }
            if(ans > N) break;
            x = (x == ans)?ans + 1:ans;
        }
        puts("-1");
    }
    int main()
    {
        Sca2(N,Q);
        for(int i = 1; i <= N ; i ++){
            Scl(a[i]); add(i,a[i]);
        } 
        while(Q--){
            int x; LL p;
            scanf("%d%lld",&x,&p);
            add(x,p - a[x]); a[x] = p;
            solve();
        }
        
        return 0;
    }
    思路2

    思路3:将跳的思路改为寻找一个最小的大于si的位置,考虑用线段树维护一下区间最大值,树状数组维护前缀和,可以优化掉一个ln

    #include <map>
    #include <set>
    #include <ctime>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <string>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <sstream>
    #include <iostream>
    #include <algorithm>
    #include <functional>
    using namespace std;
    inline int read(){int now=0;register char c=getchar();for(;!isdigit(c);c=getchar());
    for(;isdigit(c);now=now*10+c-'0',c=getchar());return now;}
    #define For(i, x, y) for(int i=x;i<=y;i++)  
    #define _For(i, x, y) for(int i=x;i>=y;i--)
    #define Mem(f, x) memset(f,x,sizeof(f))  
    #define Sca(x) scanf("%d", &x)
    #define Sca2(x,y) scanf("%d%d",&x,&y)
    #define Sca3(x,y,z) scanf("%d%d%d",&x,&y,&z)
    #define Scl(x) scanf("%lld",&x);  
    #define Pri(x) printf("%d
    ", x)
    #define Prl(x) printf("%lld
    ",x);  
    #define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
    #define LL long long
    #define ULL unsigned long long  
    #define mp make_pair
    #define PII pair<int,int>
    #define PIL pair<int,long long>
    #define PLL pair<long long,long long>
    #define pb push_back
    #define fi first
    #define se second 
    typedef vector<int> VI;
    const double eps = 1e-9;
    const int maxn = 2e5 + 10;
    const int maxm = 1e6 + 10;
    const int INF = 0x3f3f3f3f;
    const int mod = 1e9 + 7; 
    int N,Q;
    LL fa[maxn],a[maxn];
    void add(int p,int t){
        for(;p <= N ; p += p & -p) fa[p] += t;
    }
    LL getsum(int p){
        LL ans = 0;
        for(;p > 0; p -= p & -p) ans += fa[p];
        return ans;
    }
    struct Node{
        int pos;
        LL MAX;
        Node(int pos = 0,LL MAX = 0):pos(pos),MAX(MAX) {}
    };
    Node operator + (Node a,Node b){
        if(a.MAX >= b.MAX) return a;
        return b;
    }
    Node operator - (Node a,Node b){
        if(a.pos >= b.pos) return b;
        return a;
    }
    struct Tree{
        int l,r;
        Node MAX;
    }tree[maxn << 2];
    void Build(int t,int l,int r){
        tree[t].l = l; tree[t].r = r;
        if(l == r){
            tree[t].MAX.MAX = a[l];
            tree[t].MAX.pos = l;
            return;
        }
        int m = (l + r) >> 1;
        Build(t << 1,l,m); Build(t << 1 | 1,m + 1,r);
        tree[t].MAX = tree[t << 1].MAX + tree[t << 1 | 1].MAX;
    }
    void update(int t,int pos,LL val){
        if(tree[t].l == tree[t].r){
            tree[t].MAX.MAX = val;
            return;
        }
        int m = (tree[t].l + tree[t].r) >> 1;
        if(pos <= m) update(t << 1,pos,val);
        else update(t << 1 | 1,pos,val);
        tree[t].MAX = tree[t << 1].MAX + tree[t << 1 | 1].MAX;
    }
    Node query(int t,int l,int r,LL sum){
        if(l <= tree[t].l && tree[t].r <= r){
            if(tree[t].MAX.MAX < sum) return Node(INF,1e18);
            if(tree[t].l == tree[t].r) return tree[t].MAX;
            int m = (tree[t].l + tree[t].r) >> 1;
            if(tree[t << 1].MAX.MAX >= sum) return query(t << 1,l,m,sum);
            return query(t << 1 | 1,m + 1,r,sum);
        }
        int m = (tree[t].l + tree[t].r) >> 1;
        if(r <= m) return query(t << 1,l,r,sum);
        else if(l > m) return query(t << 1 | 1,l,r,sum);
        else return query(t << 1,l,m,sum) - query(t << 1 | 1,m + 1,r,sum);
    }
    
    int solve(){
        if(getsum(1) == 0) return 1;
        int s = 1;
        while(s < N){
            LL now = getsum(s);
            Node MAX = query(1,s + 1,N,now);
            if(MAX.pos == INF) return -1;
            if(getsum(MAX.pos - 1) == MAX.MAX) return MAX.pos;
            s = MAX.pos;
        }
        return -1;    
    }
    int main()
    {
        Sca2(N,Q);
        for(int i = 1; i <= N ; i ++){
            Scl(a[i]);
            add(i,a[i]);
        } 
        Build(1,1,N);
        while(Q--){
            int x; LL p;
            scanf("%d%lld",&x,&p);
            update(1,x,p);
            add(x,p - a[x]); a[x] = p;
            Pri(solve());        
        }
        return 0;
    }
  • 相关阅读:
    学习笔记26_MVC前台强类型参数
    Elasticsearch 和 solr 的区别
    Mysq索引优化(什么情况创建索引,什么情况不创建索引)
    Spring支持的常用数据库传播属性和事务隔离级别
    方法的参数传递机制
    JAVA类初始化和实例初始化
    JAVA设计模式
    CentOS 7 下安装 Nginx 服务,并开机自启动
    JAVA发送xml格式的接口请求
    JAVA接收postman的中raw的参数
  • 原文地址:https://www.cnblogs.com/Hugh-Locke/p/9977966.html
Copyright © 2011-2022 走看看