LOJ.#6468. 魔法[差分+树状数组]

题意

题目链接

分析

  • 将询问差分并不断加入颜色。

  • 每种颜色,一个位置 \(p\) 都只会走到与之左右相邻的两个位置之一,分类讨论 \(\rm |A-B|\) 的符号。

  • 实现可以使用树状数组。

  • 总时间复杂度为 \(O(nlogn)\)

代码

#include<bits/stdc++.h>
using namespace std;
#define go(u) for(int i=head[u],v=e[i].to;i;i=e[i].last,v=e[i].to)
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define pb push_back
typedef long long LL;
inline int gi() {
	int x=0,f=1;
	char ch=getchar();
	while(!isdigit(ch))	{
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(isdigit(ch)) {
		x=(x<<3)+(x<<1)+ch-48;
		ch=getchar();
	}
	return x*f;
}
template<typename T>inline bool Max(T &a,T b) {
	return a<b?a=b,1:0;
}
template<typename T>inline bool Min(T &a,T b) {
	return b<a?a=b,1:0;
}
const int N=2e5 + 7;
int n,Q;
LL ans[N];
struct querys{
	int id,p,c;
	querys(){}querys(int id,int p,int c):id(id),p(p),c(c){}
};
vector<int>G[N];
vector<querys>q[N];
struct BIT {
	LL t1[N],t2[N];
	int lowbit(int x) {
		return x&-x;
	}
	void m1(int x,int y){for(int i=x;i<=n;i+=lowbit(i)) t1[i]+=y;}
	void m2(int x,int y){for(int i=x;i<=n;i+=lowbit(i)) t2[i]+=y;}
	pair<LL,int> query(int x){
		LL r1=0;int r2=0;
		for(int i=x; i; i-=lowbit(i)) r1+=t1[i],r2+=t2[i];
		return make_pair(r1,r2);
	}
	void upd(int l,int r,int v) {
		if(l>r) return;
		m1(l,v),m1(r+1,-v);
		m2(l,1),m2(r+1,-1);
	}
} A,B;
int main(){
	n=gi(),Q=gi();
	rep(i,1,n) {
		int c=gi();
		G[c].pb(i);
	}
	
	rep(i,1,Q) {
		int p=gi(),l=gi(),r=gi();
		q[l-1].pb(querys(i,p,-1));
		q[r].pb(querys(i,p,1));
	}
	rep(i,1,n) {
		for(int j=0; j<G[i].size(); ++j) {
			if(!j)
				B.upd(1,G[i][j]-1,G[i][j]);
			if(j==(int)G[i].size()-1)
				A.upd(G[i][j],n,G[i][j]);
			else{
				int mid=(G[i][j]+G[i][j+1])/2;
				A.upd(G[i][j],mid,G[i][j]);
				B.upd(mid+1,G[i][j+1]-1,G[i][j+1]);
			}
		}
		for(auto v:q[i]) {
			pair<LL,int> ra=A.query(v.p),rb=B.query(v.p);
			ans[v.id]+=v.c*(1ll*ra.second*v.p-ra.first);
			ans[v.id]+=v.c*(rb.first-1ll*rb.second*v.p);
		}
	}
	rep(i,1,Q) printf("%lld\n",ans[i]);
	return 0;
}
posted @ 2018-10-30 19:23  fwat  阅读(187)  评论(0编辑  收藏  举报