21.5.31 t1

tag:线段树,贪心


根据贪心不难想到,每个物品都从大到小排序,然后一个区间的答案就是3个值的区间max乘起来。

所以要求的就是

\[\sum_{l\le r}max_a[l,r]\cdot max_b[l,r]\cdot max_c[l,r] \]

一个常见的套路,枚举右端点,线段树维护答案,用一个单调栈维护max的变化。

维护的时候要支持区间覆盖a/b/c,所以把 \(\sum a,b,c,ab,bc,ca,abc\) 全部记下来即可。

大常数 \(O(nlogn)\)\(2e5\) 本地 \(1.1s\)


#include<bits/stdc++.h>
using namespace std;

template<typename T>
inline void Read(T &n){
	char ch; bool flag=false;
	while(!isdigit(ch=getchar()))if(ch=='-')flag=true;
	for(n=ch^48;isdigit(ch=getchar());n=(n<<1)+(n<<3)+(ch^48));
	if(flag)n=-n;
}

enum{
	MAXN = 200005,
	MOD = 1000000007
};

inline int ksm(int base, int k=MOD-2){
	int res=1;
	while(k){
		if(k&1)
			res = 1ll*res*base%MOD;
		base = 1ll*base*base%MOD;
		k >>= 1;
	}
	return res;
}

inline int dec(int a, int b){
	// assert(0<=a and a<MOD and 0<=b and b<MOD);
	a -= b;
	if(a<0) a += MOD;
	return a;
}

inline int inc(int a, int b){
	// assert(0<=a and a<MOD and 0<=b and b<MOD);
	a += b;
	if(a>=MOD) a -= MOD;
	return a;
}

inline void ddec(int &a, int b){a = dec(a,b);}
inline void iinc(int &a, int b){a = inc(a,b);}
inline void upd(int &a, long long b){a = (a+b)%MOD;}

int n;
int a[3][MAXN], q[3][MAXN], top[3], ans;

struct node{
	int s1, s2, s3, s12, s23, s13, s123, fil1, fil2, fil3, sz;
	#define s1(x) t[x].s1
	#define s2(x) t[x].s2
	#define s3(x) t[x].s3
	#define s12(x) t[x].s12
	#define s23(x) t[x].s23
	#define s13(x) t[x].s13
	#define s123(x) t[x].s123
	#define fil1(x) t[x].fil1
	#define fil2(x) t[x].fil2
	#define fil3(x) t[x].fil3
	#define sz(x) t[x].sz
}t[MAXN<<2];

inline int lc(int x){return x<<1;}
inline int rc(int x){return x<<1|1;}

inline void Push_Up(int x){
	s1(x) = inc(s1(lc(x)),s1(rc(x)));
	s2(x) = inc(s2(lc(x)),s2(rc(x)));
	s3(x) = inc(s3(lc(x)),s3(rc(x)));
	s12(x) = inc(s12(lc(x)),s12(rc(x)));
	s23(x) = inc(s23(lc(x)),s23(rc(x)));
	s13(x) = inc(s13(lc(x)),s13(rc(x)));
	s123(x) = inc(s123(lc(x)),s123(rc(x)));
}

inline void Fill1(int x, int fil1){
	fil1(x) = fil1; 
	s1(x) = 1ll*sz(x)*fil1%MOD;
	s12(x) = 1ll*s2(x)*fil1%MOD;
	s13(x) = 1ll*s3(x)*fil1%MOD;
	s123(x) = 1ll*s23(x)*fil1%MOD;
}

inline void Fill2(int x, int fil2){
	fil2(x) = fil2;
	s2(x) = 1ll*sz(x)*fil2%MOD;
	s12(x) = 1ll*s1(x)*fil2%MOD;
	s23(x) = 1ll*s3(x)*fil2%MOD;
	s123(x) = 1ll*s13(x)*fil2%MOD;
}

inline void Fill3(int x, int fil3){
	fil3(x) = fil3;
	s3(x) = 1ll*sz(x)*fil3%MOD;
	s13(x) = 1ll*s1(x)*fil3%MOD;
	s23(x) = 1ll*s2(x)*fil3%MOD;
	s123(x) = 1ll*s12(x)*fil3%MOD;
}

inline void Push_Down(int x){
	if(~fil1(x))
		Fill1(lc(x),fil1(x)),
		Fill1(rc(x),fil1(x)),
		fil1(x) = -1;
	if(~fil2(x))
		Fill2(lc(x),fil2(x)),
		Fill2(rc(x),fil2(x)),
		fil2(x) = -1;
	if(~fil3(x))
		Fill3(lc(x),fil3(x)),
		Fill3(rc(x),fil3(x)),
		fil3(x) = -1;
}

void Build(int x, int head, int tail){
	sz(x) = tail-head+1;
	fil1(x) = fil2(x) = fil3(x) = -1;
	if(head==tail) return;
	int mid = head+tail >> 1;
	Build(lc(x),head,mid); Build(rc(x),mid+1,tail);
}

void Fill1(int x, int head, int tail, int l, int r, int fil1){
	if(l<=head and tail<=r) return Fill1(x,fil1);
	Push_Down(x);
	int mid = head+tail >> 1;
	if(l<=mid) Fill1(lc(x),head,mid,l,r,fil1);
	if(mid<r) Fill1(rc(x),mid+1,tail,l,r,fil1);
	Push_Up(x);
}

void Fill2(int x, int head, int tail, int l, int r, int fil2){
	if(l<=head and tail<=r) return Fill2(x,fil2);
	Push_Down(x);
	int mid = head+tail >> 1;
	if(l<=mid) Fill2(lc(x),head,mid,l,r,fil2);
	if(mid<r) Fill2(rc(x),mid+1,tail,l,r,fil2);
	Push_Up(x);
}

void Fill3(int x, int head, int tail, int l, int r, int fil3){
	if(l<=head and tail<=r) return Fill3(x,fil3);
	Push_Down(x);
	int mid = head+tail >> 1;
	if(l<=mid) Fill3(lc(x),head,mid,l,r,fil3);
	if(mid<r) Fill3(rc(x),mid+1,tail,l,r,fil3);
	Push_Up(x);
}

void check(int x=1, int head=1, int tail=n){
	if(head==tail){printf("%d %d %d\n",s1(x),s2(x),s3(x));return;}
	Push_Down(x);
	int mid = head+tail >> 1;
	check(lc(x),head,mid); check(rc(x),mid+1,tail);
}

inline int tp(int id){return q[id][top[id]];}

int main(){
	// freopen("1.in","r",stdin);
	// freopen("11.out","w",stdout);
	Read(n); Build(1,1,n);
	for(int i=1; i<=n; i++){
		for(int j=0; j<3; j++) Read(a[j][i]);
		for(int j=0; j<3; j++) for(int k=j+1; k<3; k++) if(a[j][i]<a[k][i]) swap(a[j][i],a[k][i]);
	}
	// for(int i=1; i<=n; i++,puts("")) for(int j=0; j<3; j++) printf("%d ",a[j][i]);puts("");
	for(int i=1; i<=n; i++){
		for(int j=0; j<3; j++)
			while(top[j] and a[j][tp(j)]<a[j][i]) top[j]--;
		Fill1(1,1,n,tp(0)+1,i,a[0][i]);
		Fill2(1,1,n,tp(1)+1,i,a[1][i]);
		Fill3(1,1,n,tp(2)+1,i,a[2][i]);
		for(int j=0; j<3; j++) q[j][++top[j]] = i;
		iinc(ans,s123(1));
		// check();puts("");
	}
	cout<<1ll*ksm(1ll*n*(n+1)/2%MOD)*ans%MOD<<'\n';
	return 0;
}
posted @ 2021-06-25 09:12  oisdoaiu  阅读(30)  评论(0编辑  收藏  举报