Ultimate Weirdness of an Array CodeForces - 671C (gcd,线段树)

大意: 定义一个数列的特征值为两个数gcd的最大值, $f(l,r)$表示数列删除区间$[l,r]$的元素后剩余元素的特征值, 求$\sum_{i=1}^n\sum_{j=i}^n{f(i,j)}$

这题感觉好难啊, 特征值没看出来要怎么处理, 直接看题解了

#include <iostream>
#include <algorithm>
#include <cstdio>
#define PER(i,a,n) for(int i=n;i>=a;--i)
#define REP(i,a,n) for(int i=a;i<=n;++i)
#define mid ((l+r)>>1)
#define lc (o<<1)
#define rc (lc|1)
#define ls lc,l,mid
#define rs rc,mid+1,r
using namespace std;
typedef long long ll;

const int N = 1e6+10, INF = 0x3f3f3f3f;
int n, mx, a[N];
struct {
	int ma,mi,tag;
	ll sum;
	void upd(int x, int t) {
		ma=mi=tag=x, sum=(ll)t*x;
	}
} tr[N<<2];
int L1[N], L2[N], R1[N], R2[N];
ll H[N];


void pu(int o) {
	tr[o].ma = max(tr[lc].ma,tr[rc].ma);
	tr[o].mi = min(tr[lc].mi,tr[rc].mi);
	tr[o].sum = tr[lc].sum+tr[rc].sum;
}
void pd(int o, int l, int r) {
	if (tr[o].tag) {
		tr[lc].upd(tr[o].tag,mid-l+1);
		tr[rc].upd(tr[o].tag,r-mid);
		tr[o].tag = 0;
	}
}
void build(int o, int l, int r) {
	if (l==r) return tr[o].upd(l,1);
	build(ls),build(rs);
	pu(o);
}
void update(int o, int l, int r, int ql, int qr, int v) {
	if (ql>qr||tr[o].mi>=v) return;
	if (ql<=l&&r<=qr&&tr[o].ma<=v) return tr[o].upd(v,r-l+1);
	pd(o,l,r);
	if (mid>=ql) update(ls,ql,qr,v);
	if (mid<qr) update(rs,ql,qr,v);
	pu(o);
}


int main() {
	scanf("%d", &n);
	REP(i,1,n) {
		int t;
		scanf("%d", &t);
		a[t] = i;
		mx = max(mx, t);
	}
	REP(i,1,mx) {
		for (int j=i; j<=mx; j+=i) if (a[j]) {
			if (!L1[i]||L1[i]>a[j]) L2[i] = L1[i], L1[i] = a[j];
			else if (!L2[i]||L2[i]>a[j]) L2[i] = a[j];
			if (R1[i]<a[j]) R2[i] = R1[i], R1[i] = a[j];
			else if (R2[i]<a[j]) R2[i] = a[j];
		}
	}
	build(1,1,n);
	PER(i,1,mx) {
		if (L1[i]!=R1[i]) {
			update(1,1,n,1,L1[i],R2[i]);
			update(1,1,n,L1[i]+1,L2[i],R1[i]);
			update(1,1,n,L2[i]+1,n,n+1);
		}
		H[i] = (ll)(n*(n+1))-tr[1].sum;
	}
	ll ans = 0;
	REP(i,1,mx-1) { 
		ans += (ll)i*(H[i+1]-H[i]);
	}
	printf("%lld\n", ans);
}

猜你喜欢

转载自www.cnblogs.com/uid001/p/10417590.html