Time Litmit: 1000ms      Memory Limit: 256MB

Description

给定一张 $N$ 个点、$M$ 条边的无向图 $G$ 。每个点有个权值$W_i$。

我们定义$G_i$ 为图 $G$ 中删除第 ii 号顶点后的图。我们想计算 $G_1,G_2,...,G_n$ 这 $N$ 张图的权值。

对于任意一张图 $G$ ,它的权值是这样定义的:

1. 如果 $G$ 是联通图,那么 $G$ 的权值为 $G$ 中所有顶点权值的乘积。

2. 如果 $G$ 是非联通图,那么 $G$ 的权值为 $G$ 中所有联通块的权值之和。

 $G$ 中的一个联通块指的是 $G$ 的一个子图,并且这个子图中的点两两相连(包括直接连接或者间接连接),并且不存在子图外的点使得子图内的点能与子图外的点相连。

Input

第一行包含两个整数 $n$ 和 $m (2≤n≤10^5,1≤m≤2×10^5)$,分别表示点数和边数。

第二行包含 $n$ 个整数 $w_1,w_2,...,w_n (1≤w_i≤10^9)$ , 表示每个顶点的权值。

接下来 $m$ 行,每行两个整数 $x_i$ 和 $y_i (1≤x_i,y_i≤n,x_i≠y_i)$, 表示一条无向边。

Output

输出只有一个整数: $S=(\sum\limits_{i=1}^{n}  i⋅z_i) mod (10^9+7)$, 其中 $z_i$ 是图 $G_i$ 的权值。

Sample Input

5 5

6 5 4 3 2

1 2

2 3

2 4

3 4

3 5

Sample Output

3216

HINT

【样例解释】

z1=120, z2=30, z3=92, z4=240, z5=360

【数据范围及约定】

子任务1(5分): n≤10,m≤20

子任务2(10分): n≤1000,m≤2000

子任务3(20分): 该图恰为一棵树,m=n−1

子任务4(20分): 该图为一幅联通图

子任务5(45分): 我们会拿最强的数据来评测你的程序 (要不要说的这么直白。。。)

对于所有数据,$2≤n≤10^5,1≤m≤2×10^5$

[吐槽]

  场上。。只搞了一个35。。

  (在思考子任务3的时候居然想到了奇妙的特判的情况感天动地qwq)

  想到tarjan然后懵掉系列。。我天感觉自己宛若一个智障qwq

[题解]

  可以看部分分找找灵感

  子任务3是可以搞一下事情的

  具体做法的话就是用一个$val_i$记录一下以$i$为根的子树的权值乘积

  然后删点的时候用总的$val$除以$val_i$然后再加上$i$的各个子树的$val$就好

  所以想,能不能将这个东西强行变成一棵树然后用树d来搞呢?

  考虑删掉一个点会发生啥事

  删掉一个点,显然会有两种情况

  1.不是割点

    那么其实删掉了对图的连通性并没有什么影响,直接在原来连通块的权值乘积里面去掉这个点的权值就好了

  2.是割点

    一个很简单粗暴的想法就是把点双跑出来,然后看这个割点会连到哪些点,然后将这个点所在的点双的贡献重新算一下

    (也就是将这些点双的贡献从原来所属的连通块里面去掉,然后再重新加到$ans$里面去)

    然而这就有问题了(如下图)

    有一种东西叫做割顶啊。。。一个点可能属于多个点双,这就很尴尬了

这时候仿佛有两种不同的方法可以解决这个问题

    

  一种方法

  对于每一个点双多搞一个代表点,然后让这个点连到点双里面的其他点

  由于点双本身的性质,两个点双最多共用一个点,所以可以十分愉快地解决上面的问题,转化成一棵树

  然后就可以愉快跑树d啦

  另一种方法(其实就是因为笔者比较傻所以想了一个绕了几个弯子的奇妙搞法。。)

  我们想要把这个图转成一棵树,所以就直接考虑把这个图当成一棵树来跑,以其dfs序来建一棵树

  

  然后就会发现奇妙的事情

  (为了方便描述,后面所讲到的后继指的是该节点在dfs树中的儿子)

  因为我们是按照dfs序建的树,所以一个点$x$的各个后继的子树中的点在原图(也就是左边的图)中不可能有边相连

  也就是说比如$x=4$, 那么以$5$为根的子树中的点(5,6,7)和以$8$为根的子树中的点(8,9)在原图中肯定没有边相连

  因为如果有边相连肯定不会出现在不同的后继的子树中

  

  接着看因为删掉了割点而变成一个新连通块的点们

  显然应该是割点的每一个后继的子树里面的点会变成一个新的连通块

  而由于之前所讲到的性质,保证了这些新连通块的权值可以用与处理树上的情况一样的方式来求出

  详细点说就是

  对于一个后继$x$,删掉割点之后$x$所在连通块的权值的乘积就应该是$val_x$

  详细的原因?

  首先$x$的子树中不会有边连到“树”中深度比割点小的点

  同时也不会有边连到$x$兄弟的子树中

  这题只需要考虑权值,跟边没有任何关系

  所以根本不用管这些点在原图中是怎么连的,只要保证这个连通块中所有点的权值都算进去了就行(爽快)

  那就直接按照树的方式统计,将连通块中的点权全部乘到$x$上就好了

  深度$<$ 割点?

  显然深度小于割点的这堆点在删除割点之后只会变成一个连通块

  其权值其实就是原来整个连通块的权值除去删掉的点的权值再除去所有割点后继的子树的权值

  实现起来就是将原来的整个连通块的$val$一直除分裂出来的新连通块的值,然后剩下的东西直接加到答案里面就好啦

  废话了一堆终于就很愉快滴(个鬼qwq)解决了这个问题啦

[一些细节]

  会发现如果说删掉的点是树根,答案会多1

  因为是树根就意味着深度比删掉点小的那个连通块是不存在的

  但是因为我们是用除法处理的所以除出来是1

  这里就要特判一下啦

 #include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define MOD 1000000007
using namespace std;
const int MAXN=1e5+;
struct xxx
{
int y,next;
}a[MAXN**];
int h[MAXN],id[MAXN],low[MAXN],dfn[MAXN],h2[MAXN],sz[MAXN];
bool st[MAXN],mark[MAXN];
ll val[MAXN],v[MAXN],valian[MAXN];
int n,m,tot,cnt,t,top;
ll ans1,ans,all;
int add(int x,int y,int *h);
int task1();
ll ksm(ll x,int b);
ll ni(ll x);
int tarjan(int rt,int x); int main()
{
// freopen("a.in","r",stdin);
// freopen("a.out","w",stdout); scanf("%d%d",&n,&m);
for (int i=;i<=n;++i) scanf("%lld",v+i);
memset(h,-,sizeof(h));
tot=;
int x,y;
for (int i=;i<=m;++i)
{
scanf("%d%d",&x,&y);
add(x,y,h); add(y,x,h);
}
task1();
} int add(int x,int y,int *h)
{
a[++tot].y=y; a[tot].next=h[x]; h[x]=tot;
} int task1()
{
for (int i=;i<=n;++i) dfn[i]=,h2[i]=-,mark[i]=false,st[i]=false;
ans=; cnt=;
for (int i=;i<=n;++i)
if (dfn[i]==)
{
ans1=; ++cnt; st[i]=true;
sz[cnt]=;
tarjan(,i);
ans=(ans+ans1)%MOD;
valian[cnt]=ans1;
}
int num,u;
ll tmp,tmp1,ansl=;
for (int i=;i<=n;++i)
{
num=id[i];
if (!mark[i])
{
tmp=(valian[num]*ni(v[i]))%MOD;
tmp=(ans+MOD-valian[num]+tmp)%MOD;
if (sz[num]==) --tmp;
}
else
{
tmp1=(valian[num]*ni(v[i]))%MOD; tmp=;
for (int j=h2[i];j!=-;j=a[j].next)
{
u=a[j].y;
if (low[u]<dfn[i]) continue;
tmp1=(tmp1*ni(val[u]))%MOD;
tmp=(tmp+val[u])%MOD;
}
tmp=(ans+MOD-valian[num]+tmp1+tmp)%MOD;
tmp=(tmp+MOD-st[i])%MOD;
}
// printf("%lld\n",tmp);
ansl=(ansl+tmp*i%MOD)%MOD;
}
printf("%lld\n",ansl);
} ll ni(ll x)
{
return ksm(x,MOD-);
} ll ksm(ll x,int b)
{
ll ret=,base=x;
while (b)
{
if (b&) ret=(ret*base)%MOD;
base=(base*base)%MOD;
b>>=;
}
return ret;
} int tarjan(int pre,int x)
{
int u,son=;
dfn[x]=low[x]=++t;
id[x]=cnt; ++sz[cnt];
ans1=(ans1*v[x])%MOD;
val[x]=v[x];
for (int i=h[x];i!=-;i=a[i].next)
{
u=a[i].y;
if (u==pre) continue;
if (!dfn[u])
{
++son;
tarjan(x,u);
add(x,u,h2);
val[x]=(val[x]*val[u])%MOD;
low[x]=min(low[x],low[u]);
if ((pre==&&son>)||(pre&&low[u]>=dfn[x]))
mark[x]=true;
}
else if (u!=pre)
low[x]=min(low[x],dfn[u]);
}
}

挫挫滴代码

【noip模拟】Fantasia的更多相关文章

  1. NOIP模拟赛20161022

    NOIP模拟赛2016-10-22 题目名 东风谷早苗 西行寺幽幽子 琪露诺 上白泽慧音 源文件 robot.cpp/c/pas spring.cpp/c/pas iceroad.cpp/c/pas ...

  2. contesthunter暑假NOIP模拟赛第一场题解

    contesthunter暑假NOIP模拟赛#1题解: 第一题:杯具大派送 水题.枚举A,B的公约数即可. #include <algorithm> #include <cmath& ...

  3. NOIP模拟赛 by hzwer

    2015年10月04日NOIP模拟赛 by hzwer    (这是小奇=> 小奇挖矿2(mining) [题目背景] 小奇飞船的钻头开启了无限耐久+精准采集模式!这次它要将原矿运到泛光之源的矿 ...

  4. 大家AK杯 灰天飞雁NOIP模拟赛题解/数据/标程

    数据 http://files.cnblogs.com/htfy/data.zip 简要题解 桌球碰撞 纯模拟,注意一开始就在袋口和v=0的情况.v和坐标可以是小数.为保险起见最好用extended/ ...

  5. 队爷的讲学计划 CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的讲学计划 题解:刚开始理解题意理解了好半天,然后发 ...

  6. 队爷的Au Plan CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的Au%20Plan 题解:看了题之后觉得肯定是DP ...

  7. 队爷的新书 CH Round #59 - OrzCC杯NOIP模拟赛day1

    题目:http://ch.ezoj.tk/contest/CH%20Round%20%2359%20-%20OrzCC杯NOIP模拟赛day1/队爷的新书 题解:看到这题就想到了 poetize 的封 ...

  8. CH Round #58 - OrzCC杯noip模拟赛day2

    A:颜色问题 题目:http://ch.ezoj.tk/contest/CH%20Round%20%2358%20-%20OrzCC杯noip模拟赛day2/颜色问题 题解:算一下每个仆人到它的目的地 ...

  9. CH Round #52 - Thinking Bear #1 (NOIP模拟赛)

    A.拆地毯 题目:http://www.contesthunter.org/contest/CH%20Round%20%2352%20-%20Thinking%20Bear%20%231%20(NOI ...

  10. CH Round #49 - Streaming #4 (NOIP模拟赛Day2)

    A.二叉树的的根 题目:http://www.contesthunter.org/contest/CH%20Round%20%2349%20-%20Streaming%20%234%20(NOIP 模 ...

随机推荐

  1. MySQL建立外键(Foreign Key)

    如果在最初建立表的时候就建立外键这样一般不会有什么问题,顺便说一下建立外键的时候,需要注意的地方. cascade方式在父表上update/delete记录时,同步update/delete掉子表的匹 ...

  2. 网页版仿Excel效果组件--handsontable拓展运用

    引言(祝看官们新年万事大吉) 前段时间项目需要实现网页版的excel表格功能,瞬间就想到了handsontable,为什么呢?理由如下:该UI组件功能齐全多样,展示效果也更贴近bootstrap风格, ...

  3. python并发编程之多进程(二):互斥锁(同步锁)&进程其他属性&进程间通信(queue)&生产者消费者模型

    一,互斥锁,同步锁 进程之间数据不共享,但是共享同一套文件系统,所以访问同一个文件,或同一个打印终端,是没有问题的, 竞争带来的结果就是错乱,如何控制,就是加锁处理 part1:多个进程共享同一打印终 ...

  4. python2 => python3 踩坑集合

    报错内容: ModuleNotFoundError: No module named 'md5' 解析: 这是 python2 的库,python3 已经把它包含进 hashlib 库里了 解决方法 ...

  5. Asp.Net Core 基于QuartzNet任务管理系统

    之前一直想搞个后台任务管理系统,零零散散的搞到现在,也算完成了. 这里发布出来,请园里的dalao批评指导! 废话不多说,进入正题. github地址:https://github.com/YANGK ...

  6. Nginx前端设置反向代理,后端Apache如何获取访客的真实IP,结合PHP

    nginx反向代理后,在应用中取得的ip都是反向代理服务器的ip,取得的域名也是反向代理配置的url的域名,解决该问题,需要在nginx反向代理配置中添加一些配置信息,目的将客户端的真实ip和域名传递 ...

  7. pep 8 规范的一些记录

    一.pep8起源 龟叔创立Python的初衷里就有创立一个容易阅读的编程语言,所以亲自操刀写了pep8 代码规范,每个项目开始前都要有一个共识,就是自己的代码规范,pep8 就是一个很好的范本. 二. ...

  8. POJ - 1321 dfs [kuangbin带你飞]专题一

    枚举行和列即可,当前已经放下cnt个棋子,当前已经搜索到第r行,如果 n - r + cnt  < k 直接退出,因为后面无法放下剩下的棋子. AC代码 #include<cstdio&g ...

  9. 《Java编程思想》读书笔记

    前言 这个月一直没更新,就是一直在读这本<Java编程思想>,这本书可以在Java业界被传神的一本书,无论谁谈起这本书都说好,不管这个人是否真的读过这本书,都说啊,这本书很好.然后再看这边 ...

  10. 【视频教程】一步步将AppBox升级到Pro版

    本系列教程分为上中下三部分,通过视频的形式讲解如何将基于FineUI(开源版)的AppBox v6.0一步一步升级FineUIPro(基础版). [视频教程]一步步将AppBox升级到Pro版(上)主 ...