• 《Gym


    看了一眼题,内行OS:不就是一个线段树板子题吗,随便过。

    仔细读题:好像不太对劲。

    分析了一段时间,可以主席树维护i的时间线,然后维护i + a[i]的最远距离就行了。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef pair<int,int> pii;
    typedef tuple<int,int,int> tu;
    const int N = 1e6 + 5;
    const int M = 2e4 + 5;
    const double eps = 1e-10;
    const LL Mod = 1e9 + 7;
    #define pi acos(-1)
    #define INF 1e9
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline int read() {
        int f = 1;int x = 0;char c = getchar();
        while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
    inline long long ADD(long long x,long long y) {return (x + y) % Mod;}
    inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;}
    inline long long MUL(long long x,long long y) {return x * y % Mod;}
    
    int n,rt[N],top = 0;
    struct Node{int L,r;LL sum;}node[N * 20];
    void Pushup(int idx) {
        node[idx].sum = node[node[idx].L].sum + node[node[idx].r].sum;
    }
    int build(int L,int r) {
        int idx = ++top;
        node[idx].sum = 0;
        if(L == r) return idx;
        int mid = (L + r) >> 1;
        node[idx].L = build(L,mid);
        node[idx].r = build(mid + 1,r);
        return idx;
    }
    int update(int L,int r,int x,int idx2) {
        int idx = ++top;
        if(top >= N * 15) {
            while(1);
        }
        node[idx] = node[idx2];
        if(L == r) {
            node[idx].sum++;
            return idx;
        }
        int mid = (L + r) >> 1;
        if(mid >= x) node[idx].L = update(L,mid,x,node[idx2].L);
        else node[idx].r = update(mid + 1,r,x,node[idx2].r);
        Pushup(idx);
        return idx;
    }
    int query(int L,int r,int ll,int rr,int idx1,int idx2) {
        if(L >= ll && r <= rr) {
            return node[idx2].sum - node[idx1].sum;
        }
        int mid = (L + r) >> 1;
        int sum = 0;
        if(mid >= ll) sum += query(L,mid,ll,rr,node[idx1].L,node[idx2].L);
        if(mid < rr) sum += query(mid + 1,r,ll,rr,node[idx1].r,node[idx2].r);
        return sum;
    }
    void solve() { 
        n = read();
        LL ans = 0;
        rt[0] = build(1,n);
        for(int i = 1;i <= n;++i) {
            int x;x = read();
            int L = max(1,i - x);
            LL ma = query(1,n,i,n,rt[L - 1],rt[i - 1]);
            ans += ma;
            rt[i] = update(1,n,min(n,x + i),rt[i - 1]);
        }
        printf("%lld
    ",ans);
    
    } 
    int main() {    
        solve();
        //system("pause");
        return 0;
    }
    View Code

    int下sum一交wa了,因为sum会爆int,一改MLE了。

    然后开始疯狂优化,甚至都想到了折半优化的证明,但是空间依然太大。开始自闭....

    走到食堂:好像可以线段树。

    于是写了个线段树上维护set。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef pair<int,int> pii;
    typedef tuple<int,int,int> tu;
    const int N = 1e6 + 5;
    const int M = 2e4 + 5;
    const double eps = 1e-10;
    const LL Mod = 1e9 + 7;
    #define pi acos(-1)
    #define INF 1e9
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline int read() {
        int f = 1;int x = 0;char c = getchar();
        while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
    inline long long ADD(long long x,long long y) {return (x + y) % Mod;}
    inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;}
    inline long long MUL(long long x,long long y) {return x * y % Mod;}
    
    int n,a[N];
    struct Node{
        int L,r,mx;
        multiset<int> S;
    }node[N << 2];
    void Pushup(int idx) {
        node[idx].S = node[idx << 1].S;
        node[idx].S.insert(node[idx << 1 | 1].S.begin(),node[idx << 1 | 1].S.end());
    }
    void build(int L,int r,int idx) {
        node[idx].L = L,node[idx].r = r,node[idx].mx = 0;
        node[idx].S.clear();
        if(L == r) return ;
        int mid = (L + r) >> 1;
        build(L,mid,idx << 1);
        build(mid + 1,r,idx << 1 | 1);
    }
    void update(int x,int val,int idx) {
        if(node[idx].L == node[idx].r) {
            node[idx].S.insert(val);
            return ;
        }
        int mid = (node[idx].L + node[idx].r) >> 1;
        if(mid >= x) update(x,val,idx << 1);
        else update(x,val,idx << 1 | 1);
        Pushup(idx);
    }
    int query(int L,int r,int low,int idx) {
        if(node[idx].L >= L && node[idx].r <= r) {
            if(node[idx].S.size() == 0) return 0;
            for(set<int> :: iterator iter = node[idx].S.begin();iter != node[idx].S.end();) {
                if(*iter >= low) break;
                else node[idx].S.erase(iter++); 
            }
            node[idx].mx = max(node[idx].mx,low);
            return node[idx].S.size();
        }
        int mid = (node[idx].L + node[idx].r) >> 1,ans = 0;
        if(mid >= L) ans += query(L,r,low,idx << 1);
        if(mid < r) ans += query(L,r,low,idx << 1 | 1);
        Pushup(idx);
        return ans;
    }
    void solve() { 
        n = read();
        for(int i = 1;i <= n;++i) a[i] = read();
        LL ans = 0;
        build(1,n,1);
        for(int i = 1;i <= n;++i) {
            int L = max(1,i - a[i]);
            LL ma = query(L,i,i,1);
            //printf("i is %d ma is %lld
    ",i,ma);
            ans += ma;
            update(i,min(n,i + a[i]),1);
        }
        printf("%lld
    ",ans);
    
    } 
    int main() {    
        solve();
      //  system("pause");
        return 0;
    }
    View Code

    en...因为删点和合并的次数太多,显然TLE了。

    这时就想到了正解:

    因为我们要维护的只是一个最远的i + a[i],那么我们假设当前每个i值维护的最远距离都满足 <= 当前i。

    那么我们在线段树中就不需要去存下所有的值了。

    当这个值不满足的时候,我们再去删去这个值对应的所有的线段树的点的代价。

    我们维护的i + a[i]显然满足一个性质:当不满足i位置的时候,那肯定也不满足[i + 1,n]的位置。

    所以此时我们就可以把他的贡献从线段树中删去。

    所以每个点只会被删去一次,我们vector记录,暴力删去点的代价,平摊后删点复杂度为NlogN。

    思维跳的还是太慢了。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef unsigned long long ULL;
    typedef pair<int,int> pii;
    typedef tuple<int,int,int> tu;
    const int N = 1e6 + 5;
    const int M = 2e4 + 5;
    const double eps = 1e-10;
    const LL Mod = 1e9 + 7;
    #define pi acos(-1)
    #define INF 1e9
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline int read() {
        int f = 1;int x = 0;char c = getchar();
        while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x<<1)+(x<<3)+(c^48);c = getchar();}
        return x*f;
    }
    inline long long ADD(long long x,long long y) {return (x + y) % Mod;}
    inline long long DEC(long long x,long long y) {return (x - y + Mod) % Mod;}
    inline long long MUL(long long x,long long y) {return x * y % Mod;}
    
    int n,a[N];
    struct Node{
        int L,r,sum;
    }node[N << 2];
    vector<int> vec[N];
    void Pushup(int idx) {
        node[idx].sum = node[idx << 1].sum + node[idx << 1 | 1].sum;
    }
    void build(int L,int r,int idx) {
        node[idx].L = L,node[idx].r = r,node[idx].sum = 0;
        if(L == r) return ;
        int mid = (L + r) >> 1;
        build(L,mid,idx << 1);
        build(mid + 1,r,idx << 1 | 1);
    }
    void update(int x,int val,int idx) {
        if(node[idx].L == node[idx].r) {
            node[idx].sum += val;
            return ;
        }
        int mid = (node[idx].L + node[idx].r) >> 1;
        if(mid >= x) update(x,val,idx << 1);
        else update(x,val,idx << 1 | 1);
        Pushup(idx);
    }
    int query(int L,int r,int low,int idx) {
        if(node[idx].L >= L && node[idx].r <= r) {
            return node[idx].sum;
        }
        int mid = (node[idx].L + node[idx].r) >> 1,ans = 0;
        if(mid >= L) ans += query(L,r,low,idx << 1);
        if(mid < r) ans += query(L,r,low,idx << 1 | 1);
        return ans;
    }
    void solve() { 
        n = read();
        for(int i = 1;i <= n;++i) a[i] = read();
        LL ans = 0;
        build(1,n,1);
        for(int i = 1;i <= n;++i) {
            int L = max(1,i - a[i]);
            LL ma = query(L,i,i,1);
            ans += ma;
            update(i,1,1);
            vec[min(n,i + a[i])].push_back(i);
            for(auto v : vec[i]) update(v,-1,1);
        }
        printf("%lld
    ",ans);
    
    } 
    int main() {    
        solve();
        system("pause");
        return 0;
    }
    View Code
  • 相关阅读:
    第二章整理
    汇编实验二
    汇编实验一
    第一章整理
    第一部分 | 第1章 —— Hello Cocos2d-x
    返回 *this 的成员函数以及 const重载
    C++中的const
    680. Valid Palindrome II
    字典树
    单调队列
  • 原文地址:https://www.cnblogs.com/zwjzwj/p/15302252.html
Copyright © 2020-2023  润新知