Tufurama CodeForces - 961E
题意:有一部电视剧有n季,每一季有ai集。问有多少对i,j存在第i季第j集也同时存在第j季第i集。
思路:核心问题还是统计对于第i季,你要统计第i行(存在多少数量,要大于i)。
线段树的维护相对而言比较暴力,树状数组的话,一开始全是1,一旦某个数过小,就会导致不构成贡献,移除就好。
线段树
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<sstream> #include<cmath> #include<stack> #include<cstdlib> #include <vector> #include<queue> using namespace std; #define ll long long #define llu unsigned long long #define INF 0x3f3f3f3f #define PI acos(-1.0) const int maxn = 2e5+5; const int mod = 1e9+7; int a[maxn]; vector<int>stk[maxn<<2]; void build(int x,int l,int r) { if(l == r) { stk[x].push_back(a[l]); return; } for(int i = l;i<=r;i++) stk[x].push_back(a[i]); sort(stk[x].begin(),stk[x].end()); int mid = (l+r)/2; build(x<<1,l,mid); build(x<<1|1,mid + 1,r); } int query(int L,int R,int l,int r,int i) { if(L > R) return 0; if(L<=l && r<=R) return stk[i].size() - (lower_bound(stk[i].begin(),stk[i].end(),L-1) - stk[i].begin()); int ans = 0; int mid = (l+r)/2; if(L <= mid) ans += query(L,R,l,mid,i<<1); if(R > mid) ans += query(L,R,mid+1,r,i<<1|1); return ans; } int main() { int n; scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); build(1,1,n); ll ans = 0; for(int i=1;i<n;i++) ans += query(i+1,min(a[i],n),1,n,1); printf("%lld ",ans); }
树状数组
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<sstream> #include<cmath> #include<stack> #include<cstdlib> #include <vector> #include<queue> using namespace std; #define ll long long #define llu unsigned long long #define INF 0x3f3f3f3f #define PI acos(-1.0) const int maxn = 2e5+5; const int mod = 1e9+7; const int N=2e5+100; int a[N],f[N]; struct node{ int x,y; }p[N]; bool cmp(node a,node b) { if(a.y==b.y) return a.x<b.x; return a.y<b.y; } void add(int x,int y) { while(x<N){ f[x]+=y; x+=x&-x; } } int query(int x) { int ans=0; while(x){ ans+=f[x]; x-=x&-x; } return ans; } int main () { int n;scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]),a[i]=min(a[i],n),p[i].x=i,p[i].y=a[i],add(i,1); sort(p+1,p+1+n,cmp); long long ans=0; int now=1; for(int i=1;i<=n;i++){ while(now<=n && p[now].y<i) add(p[now++].x,-1); ans+=query(a[i]); if(a[i]>=i) ans--; } printf("%lld ",ans/2); return 0; }