【NOIP模拟】Map
来源:互联网 发布:人人商城数据备份 编辑:程序博客网 时间:2024/06/05 17:13
Description
Solution
这是一道水题。
首先对原图进行边的双连通分量,那么很显然,在两个不同的联通分量中的点对就是不安全的点对,同在相同的连通分量中的点对就是安全点对。
那么假如有两个连通分量互相连边,那么就会有一群连通分量合并为一个大的连通分量。
那么要如何实现呢?
tarjan缩点
这是一个很显然而且很经典的想法。
先对原图用tarjan缩点(每个点存储它点的个数),然后缩完点之后就会变成一个树。之后在这个树上倍增就能得到答案。
但是要怎么处理两两点相乘的和?
很简单的容斥(其实是很闲单的数学转换)
比如说现在有四个点的权值分别为a,b,c,d,要快速得到两两之间点的乘积,用:
Code
#include<cstdio>#include<iostream>#include<cmath>#include<cstring>#include<algorithm>#define fo(i,a,b) for(i=a;i<=b;i++)#define rep(i,a) for(i=first[a];i;i=next[i])#define rep1(i,a) for(i=first1[a];i;i=next1[i])#define fod(i,a,b) for(i=a;i>=b;i--)using namespace std;typedef long long ll;const int maxn=400007;int i,j,k,l,t,n,m,cas;int first[maxn*2],next[maxn*2],last[maxn*2],num;int first1[maxn*2],next1[maxn*2],last1[maxn*2],num1;int low[maxn],dfn[maxn],stack[maxn],dfx,tou;int size[maxn],a[maxn],hhh;int b[maxn],c[maxn];bool az[maxn],bz[maxn],cz[maxn*2];ll ans,zhi,zhi1,g[maxn][21],p[maxn][21];int deep[maxn],f[maxn][21];void add(int x,int y){ last[++num]=y;next[num]=first[x],first[x]=num;}void add1(int x,int y){ last1[++num1]=y;next1[num1]=first1[x],first1[x]=num1;}void dfs1(int x,int y){ int i; deep[x]=deep[y]+1,f[x][0]=y; g[x][0]=size[y];p[x][0]=size[y]*size[y]; rep1(i,x){ if(last1[i]!=y){ dfs1(last1[i],x); } }}int lca(int x,int y){ int i;if(deep[x]<deep[y])swap(x,y);zhi=zhi1=0; fod(i,20,0)if(deep[f[x][i]]>deep[y])zhi+=g[x][i],zhi1+=p[x][i],x=f[x][i]; if(deep[x]!=deep[y])zhi+=g[x][0],zhi1+=p[x][0],x=f[x][0]; fod(i,20,0)if(f[x][i]!=f[y][i])zhi+=g[x][i]+g[y][i],zhi1+=p[x][i]+p[y][i],x=f[x][i],y=f[y][i]; if(x!=y){ zhi+=g[x][0]; zhi1+=p[x][0]; return f[x][0]; } return x;}void tarjan(int x){ int i; dfn[x]=low[x]=++dfx; stack[++stack[0]]=x; bz[x]=az[x]=1; rep(i,x){ if(!cz[(i-1)]&&!cz[(i-1)^1]){ cz[i-1]=1; if(!bz[last[i]]){ tarjan(last[i]); low[x]=min(low[x],low[last[i]]); } else if(az[last[i]])low[x]=min(low[x],dfn[last[i]]); } // else if(az[last[i]])low[x]=min(low[x],dfn[last[i]]); } if(low[x]==dfn[x]){ hhh++; while(stack[stack[0]+1]!=x){ az[stack[stack[0]]]=0; a[stack[stack[0]]]=hhh; stack[0]--; } }}int main(){ scanf("%d%d%d",&n,&m,&cas); fo(i,1,m){ scanf("%d%d",&l,&t);b[i]=l,c[i]=t; add(l,t),add(t,l); }/* if(n==m+1){ dfs1(1,0); fo(j,1,20){ fo(i,1,n)f[i][j]=f[f[i][j-1]][j-1]; } for(;cas;cas--){ scanf("%d%d",&k,&l); int o=lca(k,l); t=deep[k]+deep[l]-2*deep[o]+1; ans+=t*(t-1); } printf("%lld\n",ans); } else{*/ fo(i,1,n){ if(!bz[i]){ tarjan(i); } } fo(i,1,n){ size[a[i]]++; } fo(i,1,m){ if(a[b[i]]!=a[c[i]]){ add1(a[b[i]],a[c[i]]); add1(a[c[i]],a[b[i]]); } } tou=a[1]; dfs1(tou,0); fo(j,1,20){ fo(i,1,hhh){ f[i][j]=f[f[i][j-1]][j-1]; g[i][j]=g[f[i][j-1]][j-1]+g[i][j-1]; p[i][j]=p[f[i][j-1]][j-1]+p[i][j-1]; } } for(;cas;cas--){ scanf("%d%d",&k,&l); if(deep[a[k]]<deep[a[l]])swap(k,l); if(a[k]!=a[l]){ int o=lca(a[k],a[l]); zhi+=size[a[k]],zhi1+=(ll)size[a[k]]*size[a[k]]; if(o!=a[l])zhi+=size[a[l]],zhi1+=(ll)size[a[l]]*size[a[l]]; ans+=zhi*zhi-zhi1; } } printf("%lld\n",ans);// }}
2 0
- 【NOIP模拟】Map
- Noip模拟
- 【NOIP模拟】20151004模拟
- 【NOIP模拟】 20151005模拟
- 【NOIP模拟】 20151006模拟
- 【NOIP模拟】 20151007模拟
- 【NOIP模拟】20151014模拟
- 【NOIP模拟】20151015模拟
- 【NOIP提高组】Map
- 【09 NOIP 模拟】light
- [NOIP模拟]Day1
- 8.9CH NOIP模拟
- 8.10FCH NOIP模拟
- 8.13NOIP模拟
- 8.14NOIP模拟
- noip模拟赛 双城记
- Noip模拟总结
- 【noip模拟赛】密码
- 自定义导航栏与ViewPager的结合使用
- 追着嘟嘟学c#系列基础第四篇-----c#类和对象【蓝鸥出品】
- Find the median of two sorted arrays(找到两个排好序的数组的中位数)
- Android修改APP版本号
- RedPackage
- 【NOIP模拟】Map
- 更改tabblwView的cell的线的颜色 以及 可以单独加载某个行的数据
- 图解SQL的各种连接join[转]
- 检查Linux服务器性能的10条命令
- Python内置函数
- GUIZHOU的性能问题诊断
- [iOS 10 适配问题] 整合iOS10系统的适配相关内容
- 索引的优点和缺点
- 为web项目添加logback