2020牛客寒假算法基础集训营4 H 坐火车
https://ac.nowcoder.com/acm/contest/3005/H
当我们要计算的车厢从第i个移到第i+1个的时候
只会影响第i个车厢对应颜色的数量 和 第i+1个车厢对应颜色的数量
用树状数组维护当前车厢左右所有颜色相同的车厢对数的前缀和
假设已经计算完了前i个车厢的答案,现在要计算第i+1个车厢的答案
若车厢i的颜色是a,车厢i+1的颜色是b
除了a、b,其他颜色的左右相同的车厢对数是一样的
对颜色a来说,第i个车厢可以做 左边那个车厢了
第i个车厢后面有多少个颜色跟他一样的车厢(除去第i+1个车厢),这个颜色对答案的贡献就会增加多少
对颜色b来说,第i+1个车厢不可以做 右边那个车厢了
第i+1个车厢前面有多少个颜色跟他一样的车厢(除去第i个车厢),这个颜色对答案的贡献就会减少多少
再用两个数组记录这个即可
有一个点想了很久:
求第i个车厢后面有多少个颜色跟他一样的车厢(除去第i+1个车厢)时,可以不用管“除去第i+1个车厢”这个条件
后面也是
因为如果第i和第i+1个车厢颜色相同,一加一减恰好抵消
#include<cstdio> #include<algorithm> using namespace std; #define N 500001 #define lowbit(x) x&-x int col[N],L[N],R[N]; int suml[N],sumr[N]; long long c[N]; void add(int x,int y) { while(x<N) { c[x]+=y; x+=lowbit(x); } } long long query(int x) { long long s=0; while(x) { s+=c[x]; x-=lowbit(x); } return s; } int main() { int n; scanf("%d",&n); for(int i=1;i<=n;++i) { scanf("%d%d%d",&col[i],&L[i],&R[i]); sumr[col[i]]++; } for(int i=1;i<=n;++i) { sumr[col[i]]--; add(col[i],-suml[col[i]]); printf("%lld ",query(R[i])-query(L[i]-1)); suml[col[i]]++; add(col[i],sumr[col[i]]); } return 0; }