坐火车
题目描述
牛牛是一名喜欢旅游的同学,在来到渡渡鸟王国时,坐上了颜色多样的火车。
牛牛同学在车上,车上有 n 个车厢,每一个车厢有一种颜色。
他想知道对于每一个正整数x∈[1, n] ,集合{(i, x, j) ∣ i<x<j, l x≤col i=col j≤rx}中包含多少个元素。
换句话说,就是要求每一个车厢两边有多少对颜色相同的车厢,并且这一对车厢的颜色要在 lx 到 rx 之间。其中 coli 代表 i 号车厢的颜色,lx,rx 代表颜色的限制。
输入描述:
第一行一个正整数n。
第二行 n 个三元组,每个三元组包括三个正整数 (coli, li, ri),输入中没有括号,这 3n 个正整数之间均只用空格隔开,详见样例。
输出描述:
输出一行 n 个非负整数代表答案。
这道题思维比较难想;
解释一下题解代码:
思考的对象可以放在每次枚举的车厢的颜色上,从1–n枚举每个车厢,当前车厢的颜色为x,这个位置的车厢就不能与前面的车厢颜色为x的匹配,所有我们要减去当前位置 i 前面x的个数(因为我们之前就已经加上),还要加上当前位置 i 后面的 x 的个数(意味着这个位置 i 可以和他们匹配);
所以树状数组就是一个不错的选择;
#include<bits/stdc++.h>
#define ll long long
#define pa pair<int,int>
#define lson k<<1
#define rson k<<1|1
//ios::sync_with_stdio(false);
using namespace std;
const int N=500100;
const int M=200100;
const ll mod=998244353;
ll s1[N],s2[N],tr[N];//s1代表数i的后面还有几个数i,s2代表数i前面还有几个数i
int n;
struct Node{
int l,r,c;
}col[N];
int lowbit(int k){
return k & (-k);
}
void add(int p,ll q){//p点加上q,单点修改
while(p<=N){
tr[p]+=q;
p+=lowbit(p);
}
}
ll sum(int p){//单点查询,就是求前缀和
ll s=0;
while(p!=0){
s+=tr[p];
p-=lowbit(p);
}
return s;
}
int main(){
ios::sync_with_stdio(false);
cin>>n;
for(int i=1;i<=n;i++) cin>>col[i].c>>col[i].l>>col[i].r;
for(int i=n;i>=1;i--) s1[col[i].c]++;
for(int i=1;i<=n;i++){
s1[col[i].c]--;//后面还有几个col[i].c
add(col[i].c,-s2[col[i].c]);//减去前面col[i].c的个数
cout<<sum(col[i].r)-sum(col[i].l-1)<<" ";
s2[col[i].c]++;//前面还有几个col[i].c
add(col[i].c,s1[col[i].c]);
}
return 0;
}