《Gym - 344448C 》

看了一眼题,内行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\n",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\n",i,ma);
        ans += ma;
        update(i,min(n,i + a[i]),1);
    }
    printf("%lld\n",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\n",ans);

} 
int main() {    
    solve();
    system("pause");
    return 0;
}
View Code

 

posted @ 2021-09-16 20:57  levill  阅读(42)  评论(0编辑  收藏  举报