题目描述
牛牛是一名喜欢旅游的同学,在来到渡渡鸟王国时,坐上了颜色多样的火车。
牛牛同学在车上,车上有 n 个车厢,每一个车厢有一种颜色。
他想知道对于每一个正整数 $ x in [1, n] $ 中,集合 $ x in [1, n],{ (i, x, j) | i < x < j, l_x le col_i = col_j le r_x } $中包含多少个元素。
换句话说,就是要求每一个车厢两边有多少对颜色相同的车厢,并且这一对车厢的颜色要在$ l_x$到 $r_x$ 之间。其中 $col_i$代表 i 号车厢的颜色,$l_x,r_x$ 代表颜色的限制。
输入描述:
第一行一个正整数n。
第二行 n 个三元组,每个三元组包括三个正整数 (coli, li, ri),输入中没有括号,这 3n 个正整数之间均只用空格隔开,详见样例。
$ 1leq nleq 5 imes10^5, 1leq col_i,l_i,r_ileq 5 imes10^5. $
输出描述:
输出一行 n 个非负整数代表答案。
输入
5 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
输出
0 3 4 3 0
传送门:
https://ac.nowcoder.com/acm/contest/3005/H
思路:
首先维护一个关于颜色的前缀和$ ans $数组。$ ans[i] $代表 颜色在$ 1-i $之间的数量有多少。
如果我们已经知道$ x-1 $处的答案,如何维护这个数组得出$ x $处的答案呢?所以要加上$ x-1 $和后面的匹配数量(用$ r $数组维护)。
那么计算 $ x $处的答案之前要先减去 $ x $这点对前面的影响($ l $数组维护),为什么计算$ x $处的答案之前不减去 $ x $和后面的匹配数量呢?
因为 $ x $和后面所匹配的数量还没有加到 $ ans $数组里面。所以$ x $处的答案就是$ query(ans[r_x])-query(ans[l_x-1]) $.
代码:
1 #include<bits/stdc++.h> 2 3 using namespace std; 4 5 typedef long long ll; 6 7 ll ans[500005]; 8 ll l[500005]; 9 ll r[500005]; 10 11 struct node 12 { 13 int c; 14 int l; 15 int r; 16 17 }; 18 19 node col[500005]; 20 21 int n; 22 void add(int x, ll y) 23 { 24 for(; x <= n; x += x & -x) 25 ans[x] += y; 26 } 27 28 ll query(int x) 29 { 30 ll sum = 0; 31 for(; x; x -= x & -x) 32 sum += ans[x]; 33 return sum; 34 } 35 int main() 36 37 { 38 scanf("%d", &n); 39 40 for(int i = 1; i <= n; i++) 41 { 42 scanf("%d%d%d", &col[i].c, &col[i].l, &col[i].r); 43 r[col[i].c]++; 44 } 45 46 for(int i = 1; i <= n; i++) 47 { 48 49 add(col[i].c, -l[col[i].c]); 50 printf("%lld ", query(col[i].r) - query(col[i].l - 1) ); 51 add(col[i].c, --r[col[i].c]); 52 l[col[i].c]++; 53 } 54 }