loj #6468. 魔法

loj #6468. 魔法

题目大意还是比较清楚的吧
先考虑 l = 1 , r = n l = 1, r = n l=1,r=n怎么做
可以考虑每个魔法球对每个位置的贡献
假设当前位置为 a a a,下一个和它种类相同的魔法球位置为 b b b
m i d = a + b 2 mid = \frac{a+b}{2} mid=2a+b
那么对于 [ a , m i d ] [a,mid] [a,mid]这个区间都用 a a a来贡献(选a), [ m i d + 1 , b ] [mid + 1, b] [mid+1,b] b b b来贡献

因为求的是 ∣ p − p o s ∣ |p - pos| ppos
就分两种情况,p > pos 和 p <= pos
然后可以用几个树状数组维护一下

考虑100分怎么做
先把对于颜色 [ l , r ] [l,r] [l,r]可以拆分成 [ 1 , r ] − [ 1 , l − 1 ] [1, r] - [1, l - 1] [1,r][1,l1],然后把每个询问拆分成两个前缀和,再按照颜色从小到大排序
然后每次就把一种颜色插入序列中,再算对每个询问的贡献就好了
具体看代码吧
code:

#include<bits/stdc++.h>
#define int long long
#define N 2000005
#define lowbit(x) (x & -x)
using namespace std;
struct BIT{
	int tree[N];
	void update(int x, int y){
		for(;x < N; x += lowbit(x)) tree[x] += y;
	}
	int query(int x){
		int ret = 0;
		for(; x; x -= lowbit(x)) ret += tree[x];
		return ret;
	}
	void add(int l, int r, int x){
		if(l > r) return;
		update(l, x), update(r + 1,  - x);
	}
}L, R, Ls, Rs;//L 表示贡献点在当前点的左边, Ls 表示有几个贡献点  R,Rs同理
struct A{
	int pos, col, id, o;
}q[N];
int cmp(A x, A y){
	return x.col < y.col;
}
int n, Q, m, ANS[N];
vector<int> a[N];
signed main(){
	scanf("%lld%lld", &n, &Q);
	for(int i = 1; i <= n; i ++){
		int x;
		scanf("%lld", &x);
		a[x].push_back(i);//把每个颜色出现的位置记录下来,方便插入颜色
	}
	for(int i = 1; i <= Q; i ++){
		int p, l, r;
		scanf("%lld%lld%lld", &p, &l, &r);
		q[++ m].pos = p, q[m].col = l - 1, q[m].id = i, q[m].o = - 1;
		q[++ m].pos = p, q[m].col = r, q[m].id = i, q[m].o = 1;//拆分成前缀和的形式
	}
	sort(q + 1, q + 1 + m, cmp);
	int pos = 0;
	for(int col = 1; col <= n; col ++){
		int mm = a[col].size();
		if(mm){//如果有颜色就插入
			R.add(1, a[col][0], a[col][0]), Rs.add(1, a[col][0], 1);//考虑第一个以前的
			for(int j = 0; j < mm - 1; j ++){//中间的
				int mid = (a[col][j] + a[col][j + 1]) / 2;
				L.add(a[col][j] + 1, mid, a[col][j]), Ls.add(a[col][j] + 1, mid, 1);
				R.add(mid + 1, a[col][j + 1], a[col][j + 1]), Rs.add(mid + 1, a[col][j + 1], 1);
			}
			L.add(a[col][mm - 1] + 1, n, a[col][mm - 1]), Ls.add(a[col][mm - 1] + 1, n, 1);//最后一个往后的
		}
		while(pos + 1 <= m && q[pos + 1].col <= col){
			pos ++;
			int p = q[pos].pos;
			if(q[pos].col == col) ANS[q[pos].id] += q[pos].o * (R.query(p) - Rs.query(p) * p), ANS[q[pos].id] += q[pos].o * (Ls.query(p) * p - L.query(p));//计算贡献
		}
	}
	for(int i = 1; i <= Q; i ++) printf("%lld\n", ANS[i]);
	return 0;
}

离线大法吼哇

posted @ 2019-09-07 08:27  lahlah  阅读(20)  评论(0编辑  收藏  举报