看了一眼题,内行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; }
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; }
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; }