可爱萌新刚学二离求助呜呜呜
查看原帖
可爱萌新刚学二离求助呜呜呜
150879
quest_2楼主2021/2/20 15:27

RT,对着代码卡了一晚上+一下午的常了,还是没有什么曙光。

最后两个点T飞,前面的点都跑得飞快。

测了一下主要时间花在第二次离线上,可能是写得太丑了。

块长是贺的,快读也是贺的。

码风是vscode格式化码风,有注释。

好人一生平安。

/*sum_{l'~l-1}(bigger[1,r]-bigger[1,i-1]+(smaller[1,r]-smaller[1,i-1]+1)*num[i])*/

#include <bits/stdc++.h>
using namespace std;
const int MAX = 1e6 + 7;
struct query//原询问
{
	int l, r;
	int id;
} q[MAX];
int N, Q;
int block[MAX];//分块的块
int blockk[MAX];//莫队的块
bool cmp(query a, query b)
{
	if (blockk[a.l] != blockk[b.l])
	{
		return a.l < b.l;
	}
	return a.r < b.r;
}
struct seg//离线下来的询问
{
	int l, r;
	int id, opt;
	seg(int a = 0, int b = 0, int c = 0, int d = 0)
	{
		l = a;
		r = b;
		id = c;
		opt = d;
	}
};
vector<seg> v[MAX];//每个元素上挂的询问们
struct BIT//树状数组
{
	long long tree[MAX];
	int lowbit(int x)
	{
		return x & (-x);
	}
	void update(int x, int k)
	{
		while (x <= N)
		{
			tree[x] += k;
			x += lowbit(x);
		}
	}
	long long query(int x)
	{
		long long res = 0;
		while (x > 0)
		{
			res += tree[x];
			x -= lowbit(x);
		}
		return res;
	}
};

BIT A1, A2;//两个BIT,一个统计元素值和,一个元素个数

int ls[MAX / 300], rs[MAX / 300];//分块的块左右界
long long bigger[MAX], smaller[MAX];//比num[i]大的数值总和、比num[i]小的数值个数
struct sqrtblock//分块
{

	long long sumb[MAX / 300], sumv[MAX];//sumb大块的前缀和、sumv单个元素在块内的前缀和
	inline void update(int p, int k)
	{
		for (register int i = block[p]; i <= block[N]; i++)
		{
			sumb[i] += k;
		}
		for (register int i = p; i <= rs[block[p]]; i++)
		{
			sumv[i] += k;
		}
	}
	inline long long getcnt(int p)
	{
		return sumb[block[p] - 1] + sumv[p];
	}
};
sqrtblock B1, B2;//两个分块,一个统计元素值和,一个元素个数

inline void pre()//预处理分块
{
	int M = 317;//分块块长(贺)
	int B = N / M;//分出的块数
	int S = N / (sqrt(Q));//莫队块长
	for (register int i = 1; i <= N; i++)
	{
		block[i] = (i - 1) / M + 1;
		blockk[i] = (i - 1) / S + 1;
	}
	for (register int i = 1; i <= B; i++)
	{
		ls[i] = rs[i - 1] + 1;
		rs[i] = ls[i] + M - 1;
	}
	if (N % M)//边角料
	{
		B++;
		ls[B] = rs[B - 1] + 1;
		rs[B] = N;
	}
}

int num[MAX];
long long ans[MAX];

/*贺来的快读*/

// begin fast read template by CYJian (source: https://www.luogu.com.cn/paste/i11c3ppx)

namespace io
{
	const int __SIZE = (1 << 21) + 1;
	char ibuf[__SIZE], *iS, *iT, obuf[__SIZE], *oS = obuf, *oT = oS + __SIZE - 1, __c, qu[55];
	int __f, qr, _eof;
#define Gc() (iS == iT ? (iT = (iS = ibuf) + fread(ibuf, 1, __SIZE, stdin), (iS == iT ? EOF : *iS++)) : *iS++)
	inline void flush()
	{
		fwrite(obuf, 1, oS - obuf, stdout), oS = obuf;
	}
	inline void gc(char &x) { x = Gc(); }
	inline void pc(char x)
	{
		*oS++ = x;
		if (oS == oT)
			flush();
	}
	inline void pstr(const char *s)
	{
		int __len = strlen(s);
		for (__f = 0; __f < __len; ++__f)
			pc(s[__f]);
	}
	inline void gstr(char *s)
	{
		for (__c = Gc(); __c < 32 || __c > 126 || __c == ' ';)
			__c = Gc();
		for (; __c > 31 && __c < 127 && __c != ' '; ++s, __c = Gc())
			*s = __c;
		*s = 0;
	}
	template <class I>
	inline bool gi(I &x)
	{
		_eof = 0;
		for (__f = 1, __c = Gc(); (__c < '0' || __c > '9') && !_eof; __c = Gc())
		{
			if (__c == '-')
				__f = -1;
			_eof |= __c == EOF;
		}
		for (x = 0; __c <= '9' && __c >= '0' && !_eof; __c = Gc())
			x = x * 10 + (__c & 15), _eof |= __c == EOF;
		x *= __f;
		return !_eof;
	}
	template <class I>
	inline void print(I x)
	{
		if (!x)
			pc('0');
		if (x < 0)
			pc('-'), x = -x;
		while (x)
			qu[++qr] = x % 10 + '0', x /= 10;
		while (qr)
			pc(qu[qr--]);
	}
	struct Flusher_
	{
		~Flusher_() { flush(); }
	} io_flusher_;
} // namespace io
using io::gc;
using io::gi;
using io::gstr;
using io::pc;
using io::print;
using io::pstr;

// end fast read template by CYJian

int tmp[MAX];//离散化数组
void lsh()//离散化
{
	sort(tmp + 1, tmp + 1 + N);
	for (register int i = 1; i <= N; i++)
	{
		num[i] = lower_bound(tmp + 1, tmp + 1 + N, num[i]) - tmp;
	}
}
signed main()
{
	cin >> N >> Q;
	for (register int i = 1; i <= N; i++)
	{
		gi(num[i]);
		tmp[i] = num[i];
	}
	pre();
	lsh();
	for (register int i = 1; i <= N; i++)//预处理num[i]在[1,i-1]中的贡献
	{
		A1.update(num[i], tmp[num[i]]);
		bigger[i] = A1.query(N) - A1.query(num[i]);
		smaller[i] = A2.query(num[i] - 1);
		A2.update(num[i], 1);
	}
	for (register int i = 1; i <= Q; i++)
	{
		gi(q[i].l);
		gi(q[i].r);
		q[i].id = i;
	}
	sort(q + 1, q + 1 + Q, cmp);
	int L = 1, R = 0;
	for (register int i = 1; i <= Q; i++)//空跑莫队,刷询问
	{
		if (L > q[i].l)
		{
			v[R].push_back(seg(q[i].l, L - 1, q[i].id, 1));
		}
		while (L > q[i].l)
		{
			L--;
			ans[q[i].id] -= (bigger[L] + (smaller[L] - 1) * tmp[num[L]]);//tmp[num[i]]就是元素离散化前的值了
		}
		if (R < q[i].r)
		{
			v[L - 1].push_back(seg(R + 1, q[i].r, q[i].id, -1));
		}
		while (R < q[i].r)
		{
			R++;
			ans[q[i].id] += (bigger[R] + (smaller[R] + 1) * tmp[num[R]]);
		}
		if (L < q[i].l)
		{
			v[R].push_back(seg(L, q[i].l - 1, q[i].id, -1));
		}
		while (L < q[i].l)
		{
			ans[q[i].id] += (bigger[L] + (smaller[L] - 1) * tmp[num[L]]);
			L++;
		}
		if (R > q[i].r)
		{
			v[L - 1].push_back(seg(q[i].r + 1, R, q[i].id, 1));
		}
		while (R > q[i].r)
		{
			ans[q[i].id] -= (bigger[R] + (smaller[R] + 1) * tmp[num[R]]);
			R--;
		}
	}
    
	for (register int i = 1; i <= N; i++)//第二次离线,大概率这里写屎了
	{
		B1.update(num[i], tmp[num[i]]);
		B2.update(num[i], 1);
        
		for (register int j = 0; j < v[i].size(); j++)//扫一遍数组,处理挂着的询问
		{
			seg t = v[i][j];
			for (register int k = t.l; k <= t.r; k++)
			{
				ans[t.id] += t.opt * (B1.getcnt(N) - B1.getcnt(num[k]) + (B2.getcnt(num[k] - 1) * tmp[num[k]]));
			}
		}
	}
    
	for (register int i = 1; i <= Q; i++)//前缀和
	{
		ans[q[i].id] += ans[q[i - 1].id];
	}
	for (register int i = 1; i <= Q; i++)
	{
		cout << ans[i] << '\n';
	}
}
2021/2/20 15:27
加载中...