简化一下题意,我们先看成一副强连通的图,这时候应该是最简单了,去点任意点都是其他的乘积。那再加强一点难度,改为两个强连通图连接的非强连通图呢?那应该就是找出关键的那个点,并求出两边的乘积。但是一个一个去找是不可能的。

假设如图中的非绿色线是题目给的图。然后我们根据强连通分量去新建一副如图中绿色线条的图,那么这时候我们就把原图转化为以可树了。。对于每一个点我们求的是该点以及以下的乘积。然后我们从A出发这时候我们发现A点的值刚好就是整幅图的乘积。这时候如果我们需要求删除3这个点的得到的结果应该就是整一副图去除以3点及一下的乘积得到1,2的乘积,再加上3点的子树的乘积和也就是4、5 和 6、7的乘积和。

这道题目的难点就是转化建图的那一个步骤,应该说是最核心的部分。

#include<bits/stdc++.h>
#define LL long long
using namespace std; const int maxn = 1e5 + ;
const LL mod = 1e9 + ; LL n, w[maxn], vis[maxn << 1], sum[maxn << 1], pro[maxn << 1]; struct oldEdge{
int v, next;
bool flag;
};
int oldHead[maxn], ocnt;
oldEdge oedge[maxn << ]; void addOldEdge(int u, int v){
oedge[ocnt].v = v;
oedge[ocnt].flag = false;
oedge[ocnt].next = oldHead[u];
oldHead[u] = ocnt ++;
} struct newEdge{
int v, next;
};
int newHead[maxn << ], ncnt;
newEdge nedge[maxn << ]; void addNewEdge(int u, int v){
nedge[ncnt].v = v;
nedge[ncnt].next = newHead[u];
newHead[u] = ncnt ++;
} int dfn[maxn], low[maxn], root[maxn], rn, cnt;
stack<int>sta; void tarjan(int u, int fa){
dfn[u] = low[u] = ++cnt;
for(int i = oldHead[u]; i != -; i = oedge[i].next){
if(oedge[i].flag) continue;
oedge[i].flag = oedge[i ^ ].flag = true;
sta.push(i);
int v = oedge[i].v; if(dfn[v]){
low[u] = min(low[u], dfn[v]);
continue;
}
tarjan(v, fa);
low[u] = min(low[u], low[v]); if(low[v] >= dfn[u]){
rn ++;
int ek;
do{
ek = sta.top();sta.pop();
root[oedge[ek].v] = root[oedge[ek ^ ].v] = fa;
addNewEdge(rn, oedge[ek].v); addNewEdge(oedge[ek].v, rn);
addNewEdge(rn, oedge[ek ^ ].v); addNewEdge(oedge[ek ^ ].v, rn);
}while(oedge[ek ^ ].v != u);
}
}
} void dfs(int u){
vis[u] = true;
sum[u] = ;
pro[u] = (u <= n) ? w[u] : ;
for(int i = newHead[u]; i != -; i = nedge[i].next){
int v = nedge[i].v;
if(vis[v]) continue;
dfs(v);
if(u <= n)
sum[u] = (sum[u] + pro[v]) % mod;
pro[u] = pro[u] * pro[v] % mod;
}
} LL inv(LL a){
int p = mod - ;
LL ret = ;
while(p){
if(p & )ret = ret * a % mod;
a = a * a % mod;
p >>= ;
}
return ret;
} void init(){
memset(root, , sizeof(root));
memset(newHead, -, sizeof(newHead));
memset(oldHead, -, sizeof(oldHead));
memset(dfn, , sizeof(dfn));
memset(vis, false, sizeof(vis));
ncnt = ocnt = cnt = ;
} int main(){
int T, m, a, b;scanf("%d",&T);
while(T --){
scanf("%lld%d",&n,&m);
init();rn = n;
for(int i = ; i <= n; i ++)scanf("%lld",&w[i]);
for(int i = ; i < m; i ++){
scanf("%d%d",&a,&b);
addOldEdge(a,b);
addOldEdge(b,a);
}
for(int i = ; i <= n; i ++)
if(!dfn[i])tarjan(i, rn + ); LL tot = ;
for(int i = ; i <= n; i ++){
if(vis[i]) continue;
if(root[i]){
dfs(root[i]);
tot = (tot + pro[root[i]]) %mod;
}else
tot = (tot + w[i]) % mod;
}
LL ans = ;
for(int i = ; i <= n; i ++){
if(root[i]){
LL temp = ((tot - pro[root[i]] + pro[root[i]] * inv(pro[i]) + sum[i]) % mod + mod) * i % mod;
ans = (ans + temp) % mod;
}
else
ans = ((ans + (tot - w[i]) * i) % mod + mod) % mod;
}
printf("%lld\n",ans);
}
return ;
}

Fantasia (点强连通分量建图 + 树形DP)的更多相关文章

  1. bzoj 4871: [Shoi2017]摧毁“树状图” [树形DP]

    4871: [Shoi2017]摧毁"树状图" 题意:一颗无向树,选两条边不重复的路径,删去选择的点和路径剩下一些cc,求最多cc数. update 5.1 : 刚刚发现bzoj上 ...

  2. 【HDU5934】Bomb——有向图强连通分量+重建图

    题目大意 二维平面上有 n 个爆炸桶,i−thi-thi−th爆炸桶位置为 (xi,yi)(x_i, y_i)(xi​,yi​) 爆炸范围为 rir_iri​ ,且需要 cic_ici​ 的价格引爆, ...

  3. 强连通 反向建图 hdu3639

    Hawk-and-Chicken Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  4. poj1949Chores(建图或者dp)

    /* 题意:n个任务,有某些任务要在一些任务之前完成才能开始做! 第k个任务的约束只能是1...k-1个任务!问最终需要最少的时间完成全部的 任务! 思路:第i个任务要在第j个任务之前做,就在i,j之 ...

  5. 深探树形dp

    看到同学在写一道树形dp,好奇直接拿来写,发现很不简单. 如图,看上去是不是很像选课,没错这不是选课,升级版吧,多加了点东西罢了.简单却调了一晚上和一上午. 思路:很简单强联通分量+缩点+树形dp.直 ...

  6. Tarjan算法 求 有向图的强连通分量

    百度百科 https://baike.baidu.com/item/tarjan%E7%AE%97%E6%B3%95/10687825?fr=aladdin 参考博文 http://blog.csdn ...

  7. poj 2186 tarjan求强连通分量

    蕾姐讲过的例题..玩了两天后才想起来做 貌似省赛之后确实变得好懒了...再努力两天就可以去北京玩了! 顺便借这个题记录一下求强连通分量的算法 1 只需要一次dfs 依靠stack来实现的tarjan算 ...

  8. POJ 3107.Godfather 树形dp

    Godfather Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 7536   Accepted: 2659 Descrip ...

  9. Tarjan算法初探 (1):Tarjan如何求有向图的强连通分量

    在此大概讲一下初学Tarjan算法的领悟( QwQ) Tarjan算法 是图论的非常经典的算法 可以用来寻找有向图中的强连通分量 与此同时也可以通过寻找图中的强连通分量来进行缩点 首先给出强连通分量的 ...

随机推荐

  1. 使用@import导入实现了ImportBeanDefinitionRegistrar接口的类,不能被注册为bean

    今天在调试公司spring项目的时候发现了这样一个问题,由于我们的项目使用的是springboot就以springboot为例,代码如下: @Import({DataSourceRegister.cl ...

  2. npm的源改成淘宝镜像

    修改源地址为淘宝 NPM 镜像npm config set registry http://registry.npm.taobao.org/ 修改源地址为官方源npm config set regis ...

  3. Pandas之Dateframe 实现Excel读取与写入

    目的:有时需对数据进行到出到Excel,直观的给别人参阅,或从Excel中读取数据进行操作和分析依赖库 pandas 可简单的读出和写入 1,根据Excel读取( 需安装xlrd库) import n ...

  4. router 设置时 模板的新引法

    { path: '/Index1', name: 'Index', component: () => import ('@/components/Index.vue') },

  5. logback 常用配置详解(序)logback 简介

    转自:http://aub.iteye.com/blog/1101260 logback 简介 Ceki Gülcü在Java日志领域世界知名.他创造了Log4J ,这个最早的Java日志框架即便在J ...

  6. vue项目引用 iView 组件——全局安装与按需加载

    框架的热度,出现了不少基于Vue的UI组件库,这次项目用到了 iView 这个组件库.使用方法官网很详细. 官网:https://www.iviewui.com/ 这篇文章主要是记录一下npm 全局安 ...

  7. redgate的mysql架构比较和数据比较工具

    redgate的mysql架构比较和数据比较工具 最近线上数据需要进行架构比较,比较两个服务器上的mysql实例上数据库的架构 数据比较可以用percona的pt-table-checksum和pt- ...

  8. 腾讯游戏DBA团队的发展自白

    BA这个岗位跟仓管员很像,就是每天给别人发点货,别人在你这儿放点货,DBA工作就是把货尽快给送出去或者让人家尽快放进来.当然,还有一份重要的工作,就是让仓库里摆放的货物尽可能整齐,这也是仓管员的本职工 ...

  9. GUI库之Tkinter组件(二)

    一.Lable组件 Lable组件是用于在界面上输出描述的标签: 1.举个例子. # Lable组件 from tkinter import * root = Tk() root.title(&quo ...

  10. GUI库之认识Tkinter(一)

    一.介绍 Tkinter是Python默认的GUI库,我们经常使用的IDLE就是用Tkinter设计出来的,因此我们在使用的时候直接导入Tkinter模块就好了. 1.特点:可移植性.灵活性高 2.构 ...