题目链接:http://47.100.29.252:5283/problem/2003
思路:我们只需要设法维护:对于当前下标 ,每种颜色在 左右两侧的出现次数的乘积,再对每种颜色的乘积求和即为答案。
开两个桶维护 左侧和右侧每种颜色 的车厢数,关键在怎么填这两个桶,我们从先将填满,然后考虑从左向右移动时对的贡献即可,然后用线段树维护乘积求和即可。
#include <iostream>
#include <stdio.h>
using namespace std;
#define ll long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define mid (l+r)>>1
#define abb int l,int r,int rt
const int N = 5e5 + 7;
ll lazy[N<<2], sum[N<<2], cntl[N], cntr[N];
inline void pushup(int rt)
{
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
inline void update(int p, abb)
{
if(l == r)
{
sum[rt] = cntl[p] * cntr[p];
return ;
}
int m = mid;
if(p <= m) update(p, lson);
else update(p, rson);
pushup(rt);
}
inline ll query(int L, int R, abb)
{
if(L <= l && R >= r) return sum[rt];
int m = mid;
ll ret = 0;
if(L <= m) ret += query(L, R, lson);
if(R > m) ret += query(L, R, rson);
return ret;
}
int n, c[N], l[N], r[N];
int main()
{
scanf("%d",&n);
for(int i = 1; i <= n; i++)
scanf("%d%d%d",&c[i], &l[i], &r[i]), cntr[c[i]]++;
for(int i = 1; i <= n; i++)
{
cntr[c[i]]--; update(c[i], 1, n, 1);
cout << query(l[i], r[i], 1, n, 1) << ' ';
cntl[c[i]]++; update(c[i], 1, n, 1);
}
return 0;
}