题意:给出一个图,求$\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的更多相关文章

  1. BZOJ.5407.girls/CF985G. Team Players(三元环计数+容斥)

    题面 传送门(bzoj) 传送门(CF) \(llx\)身边妹子成群,这天他需要从\(n\)个妹子中挑出\(3\)个出去浪,但是妹子之间会有冲突,表现为\(i,j\)之间连有一条边\((i,j)\), ...

  2. CodeForces985G Team Players

    G. Team Players time limit per test 2 seconds memory limit per test 256 megabytes input standard inp ...

  3. Codeforces 985G. Team Players

    Description 有 \(n\) 个人 , \(m\) 对人有冲突 , 你要从这 \(n\) 个人中选出三个人成为一组 , 使得同一组的人不存在一对有冲突 题面 Solution 容斥 答案=总 ...

  4. Codeforces 985G - Team Players(三元环)

    Codeforces 题目传送门 & 洛谷题目传送门 真·ycx 做啥题我就做啥题 考虑枚举 \(j\),我们预处理出 \(c1_i\) 表示与 \(i\) 相连的编号 \(<i\) 的 ...

  5. Ten Qualities of an Effective Team Player

    If you were choosing team members for a business team in your organization, who would the best team ...

  6. Model--汇总

    NSFileManager.NSURL.NSFileHandle.NSData.NSXMLParser.NSUserDefaults.NSKeyedArchiver.NSKeyedUnarchiver ...

  7. 《C#本质论》读书笔记(14)支持标准查询操作符的集合接口

      14.2.集合初始化器 使用集合初始化器,程序员可以采用和数组相似的方式,在集合的实例化期间用一套初始的成员来构造这个集合. 如果没有集合初始化器,就只有在集合实例化后才能显示添加到集合中--例如 ...

  8. ng-repeat的group

     http://blog.csdn.net/violet_day/article/details/17023219 一.obj包含 <!doctype html> <html ng- ...

  9. ios9基础知识(技能篇)

    NSFileManager.NSURL.NSFileHandle.NSData.NSXMLParser.NSUserDefaults.NSKeyedArchiver.NSKeyedUnarchiver ...

随机推荐

  1. JS对象操作

    一.String常用操作 1.截取 substr(start,length) //返回从指定位置开始的指定长度的字符串. substring(start,end) //返回两个指定的位置之间的字符串. ...

  2. python初步学习-python数据类型-字典(dict)

    字典 字典类似于你通过联系人名字查找地址和联系人详细情况的地址簿,即,我们把键(名字)和值(详细情况)联系在一起.注意,键必须是唯一的,就像如果有两个人恰巧同名的话,你无法找到正确的信息. 注意,你只 ...

  3. C++之指针,引用与数组

    引用只是对象的另一个名字,通过在变量名前面添加"&”符号来定义,而指针保存的是另一个对象的地址,它们两都提供了间接访问所服务变量的途径. 但是它们的差别还是挺大的: 先从它们的值说起 ...

  4. defconfig file 的 位置

    Platform MSM8917 MSM8937 defconfig file position Android/kernel/msm-3.18/arch/arm/configs/

  5. Django===django工作流

    通过一张图来总结一下Django 的处理过程: URL 组成: 协议类型: HTTP/HTTPS HTTP 协议(HyperText Transfer Protocol,超文本传输协议)是用于从WWW ...

  6. Linux内核基础--事件通知链(notifier chain)【转】

    转自:http://blog.csdn.net/wuhzossibility/article/details/8079025 内核通知链 1.1. 概述 Linux内核中各个子系统相互依赖,当其中某个 ...

  7. Visual Studio 附加到进程调试

    Visual Studio 果然是强大的,今天第一次使用附加到进程调试的功能!但是,在使用的时候发现进不了断点... 解决方案: 1.发布的时候选择Debug,而不是Release: 2.右键项目-& ...

  8. Vim配置Node.js开发工具

    ubuntu安装vim编辑器.默认情况下,vim在运行的时候会加载-/.vimrc文件里的配置文件,如果在-目录下不存在这个配置文件可以手动创建. 在-/.vim目录下是vim的插件加载的位置,可以在 ...

  9. Fel表达式使用过程中需要注意的问题

    精度问题: 我们知道java中直接使用float和double参与的计算都可能会产生精度问题,比如0.1+0.3.1.0-0.9 等.所以一般财务系统,都会使用BigDecimal进行加减乘除. 在调 ...

  10. 线程同步工具 Semaphore类使用案例

    参考博文 : 线程同步工具(一) 线程同步工具(二)控制并发访问多个资源 并发工具类(三)控制并发线程数的Semaphore 使用Semaphore模拟互斥锁 当一个线程想要访问某个共享资源,首先,它 ...