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\n",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\n",ans/2);
return 0;
}