[CF985G]Team Players

匿名 (未验证) 提交于 2019-12-03 00:39:02

题意:给出一个图,求$\sum\limits_{\substack{i\lt j\lt k\\\nexists(i,j),(j,k),(i,k)}}Ai+Bj+Ck$

挺好的一道题==,就是稍微毒了点

考虑容斥,先算$all=\sum\limits_{i\lt j\lt k}Ai+Bj+Ck$

我们枚举$0\leq t\leq n-1$,它作为$i$被计数$\binom{n-1-i}2$次,作为$j$被计数$i(n-1-i)$次,作为$k$被计数$\binom i2$次,直接统计即可

再算$sub_1=\sum\limits_{\substack{i\lt j\lt k\\\exists(i,k)\text{or}(j,k)}}Ai+Bj+Ck$

我们枚举$k$和$x\left(x\lt k,\exists(x,k)\right)$,如果$i=x$,那么$j\in[x+1,k-1]$,如果$j=x$,那么$i\in[0,x-1]$,直接统计就好了

这样重复统计了$\exists(i,k),(j,k)$的情况,我们把$k$的邻居排序后统计一下即可

最后算$sub_2=\sum\limits_{\substack{i\lt j\lt k\\\exists(i,j),\nexists(i,k),(j,k)}}Ai+bj+Ck$

这一部分也用容斥做,拆成$[\exists(i,j)]-[\exists(i,j),(i,k)]-[\exists(i,j),(j,k)]+[\exists(i,j),(i,k),(j,k)]$

第一部分:把所有$(i,j)$排序后从小到大枚举$k$单调地更新答案即可

第二部分:枚举$(i,k)$,在$i$的邻接表中查询$[i+1,k-1]$的节点和,这个维护前缀和就可以了

第三部分:枚举$(j,k)$,在$j$的邻接表中查询$[0,j-1]$的节点和,同样维护前缀和即可

第四部分:相当于是图中的三元环计数,题解给了一个挺不错的idea,或许能用在其他地方

我们把所有点按度数分类,度数$\geq\sqrt m$称为重点,否则称为钦轻点,显然重点只有$O(\sqrt m)$个

对每个重点$i$预处理出邻接矩阵$cn_{i,j}$,这里用bitset存是毫无压力的

我们枚举$k$,如果$k$是重点,那么直接枚举所有$(i,j)$并检查$cn_{k,i}$和$cn_{k,j}$即可,这一步的时间复杂度是$O(m\sqrt m)$的

如果$k$是轻点,那么先枚举$j(j\lt k,\exists(j,k))$

如果$j$是重点,那么直接枚举$i(i\lt j,\exists(i,k))$并用$cn_{j,i}$判断即可,这里的复杂度是$O\left(\sum\limits_{i\,是轻点}deg_i^2\right)=O\left(\sqrt m\sum\limits_{i\,是轻点}deg_i\right)=O(m\sqrt m)$(因为用$\sqrt m$替换$deg_i$,所以这里不是满的)

如果$j$是轻点,我们先给所有$j$的邻居打上标记,然后再枚举$i(i\lt j,\exists(i,k))$并用之前打上的标记判断即可,枚举$i,j$的时间复杂度同上,打标记的时间复杂度可以这样分析:因为$j$会被执行这种操作$O(deg_j)$次,而每次打标记花费$O(deg_j)$的时间,所以时间复杂度仍然同上

最后的答案就是$all-sub_1-sub_2$了

总时间复杂度$O(m\sqrt m)$,后面几个部分都卡到这里了,不得不说还是有点巧妙的...

#include<stdio.h> #include<algorithm> #include<vector> #include<bitset> using namespace std; typedef unsigned long long ll; vector<int>g[200010]; int n,m; ll A,B,C; ll C2(ll n){return n*(n-1)/2;} ll S(ll l,ll r){return l<=r?(l+r)*(r-l+1)/2:0;} ll all(){ 	int i; 	ll s=0; 	for(i=0;i<n;i++)s+=A*i*C2(n-1-i)+B*i*i*(n-1-i)+C*i*C2(i); 	return s; } int t[200010]; ll sub1(){ 	int i,j,M; 	ll s=0,cnt; 	for(i=0;i<n;i++){ 		M=0; 		for(int x:g[i]){ 			if(x<i){ 				M++; 				t[M]=x; 				s+=(i-x-1)*(A*x+C*i)+B*S(x+1,i-1)+x*(B*x+C*i)+A*S(0,x-1); 			} 		} 		cnt=0; 		for(j=2;j<=M;j++){ 			cnt+=t[j-1]; 			s-=(j-1)*(B*t[j]+C*i)+A*cnt; 		} 	} 	return s; } struct edge{ 	int x,y; 	edge(int a=0,int b=0){x=a;y=b;} }e[200010]; bool operator<(edge a,edge b){return a.y<b.y;} vector<ll>sum[200010]; int h[200010]; struct pr{ 	int l,r; 	pr(int a=0,int b=0){l=a;r=b;} }p; pr query(int i,int l,int r){ 	if(g[i].empty()||l>r)return 0; 	r=upper_bound(g[i].begin(),g[i].end(),r)-g[i].begin()-1; 	if(r<0)return 0; 	l=lower_bound(g[i].begin(),g[i].end(),l)-g[i].begin()-1; 	if(l<0)return pr(r+1,sum[i][r]); 	return pr(r-l,sum[i][r]-sum[i][l]); } int he[200010]; bool cur[200010]; bitset<200000>cn[1000]; const int bl=450; ll sub2(){ 	ll ts,s0,s1,s2,s3,sab; 	int i,j,N; 	sort(e+1,e+m+1); 	sab=s0=ts=0; 	j=1; 	for(i=0;i<n;i++){ 		s0+=sab+i*ts*C; 		while(j<=m&&e[j].y==i){ 			sab+=e[j].x*A+e[j].y*B; 			ts++; 			j++; 		} 	} 	s1=0; 	for(i=1;i<=m;i++){ 		p=query(e[i].x,e[i].x+1,e[i].y-1); 		s1+=p.l*(A*e[i].x+C*e[i].y)+B*p.r; 	} 	s2=0; 	for(i=1;i<=m;i++){ 		p=query(e[i].x,0,e[i].x-1); 		s2+=p.l*(B*e[i].x+C*e[i].y)+A*p.r; 	} 	N=0; 	for(i=0;i<n;i++){ 		if(g[i].size()>=bl){ 			he[i]=++N; 			for(int x:g[i])cn[N][x]=1; 		} 	} 	s3=0; 	for(i=0;i<n;i++){ 		if(he[i]){ 			for(j=1;j<=m&&e[j].y<i;j++){ 				if(cn[he[i]][e[j].x]&&cn[he[i]][e[j].y])s3+=A*e[j].x+B*e[j].y+C*i; 			} 		}else{ 			for(int k:g[i]){ 				if(k>=i)break; 				if(he[k]){ 					for(int j:g[i]){ 						if(j>=k)break; 						if(cn[he[k]][j])s3+=A*j+B*k+C*i; 					} 				}else{ 					for(int j:g[k])cur[j]=1; 					for(int j:g[i]){ 						if(j>=k)break; 						if(cur[j])s3+=A*j+B*k+C*i; 					} 					for(int j:g[k])cur[j]=0; 				} 			} 		} 	} 	return s0-s1-s2+s3; } int main(){ 	int i,j,x,y; 	scanf("%d%d%I64u%I64u%I64u",&n,&m,&A,&B,&C); 	for(i=1;i<=m;i++){ 		scanf("%d%d",&x,&y); 		g[x].push_back(y); 		g[y].push_back(x); 		if(x>y)swap(x,y); 		e[i]=edge(x,y); 	} 	for(i=0;i<n;i++){ 		if(!g[i].empty()){ 			sort(g[i].begin(),g[i].end()); 			sum[i].push_back(g[i][0]); 			for(j=1;j<(int)g[i].size();j++)sum[i].push_back(sum[i][j-1]+g[i][j]); 		} 	} 	printf("%I64u",all()-sub1()-sub2()); }

[CF985G]Team Players

原文:https://www.cnblogs.com/jefflyy/p/9270530.html

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!