There is a connected undirected graph with weights on its edges. It is guaranteed that each edge appears in at most one simple cycle.

Assuming that the weight of a weighted spanning tree is the sum of weights on its edges, define V(k) V(k)

as the weight of the k k

-th smallest weighted spanning tree of this graph, however, V(k) V(k)

would be defined as zero if there did not exist k k

different weighted spanning trees.

Please calculate (∑ k=1 K k⋅V(k))mod2 32  (∑k=1Kk⋅V(k))mod232

.

InputThe input contains multiple test cases.

For each test case, the first line contains two positive integers n,m n,m

(2≤n≤1000,n−1≤m≤2n−3) (2≤n≤1000,n−1≤m≤2n−3)

, the number of nodes and the number of edges of this graph.

Each of the next m m

lines contains three positive integers x,y,z x,y,z

(1≤x,y≤n,1≤z≤10 6 ) (1≤x,y≤n,1≤z≤106)

, meaning an edge weighted z z

between node x x

and node y y

. There does not exist multi-edge or self-loop in this graph.

The last line contains a positive integer K K

(1≤K≤10 5 ) (1≤K≤105)

.OutputFor each test case, output " Case #x x

: y y

" in one line (without quotes), where x x

indicates the case number starting from 1 1

and y y

denotes the answer of corresponding case.Sample Input

4 3
1 2 1
1 3 2
1 4 3
1
3 3
1 2 1
2 3 2
3 1 3
4
6 7
1 2 4
1 3 2
3 5 7
1 5 3
2 4 1
2 6 2
6 4 5
7

Sample Output

Case #1: 6
Case #2: 26
Case #3: 493

题意:给一个仙人掌,求前K小的生成树的值之和。

思路:由于是仙人掌,即每个环去掉一条边才能得到生成树,那么就算每个环贡献一个数,求前K大。

每个集合贡献一个,求前K大我们可以用K路归并。 从左到右两两合并,因为最后只要K个数,那么K以后的就不用保存了,所以每次合并最多保留K个数,则合并完的复杂度为O(NK);

K路归并:当假设答案集合为A,新集合为B。那么对于B的每个数i,先把bi+a0放入大根堆里,然后开始操作:每次取队首X放入答案集合里,然后把对应的bi+a(j+1)又插入堆里,因为它是关于bi的最大的小于X的数,这样一直操作可以保证是最大的K个。 (和“超级钢琴”那题一样,如果用了一个数X,我才把它分裂后的数(小于X)拿来考虑)。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
using namespace std;
const int maxn=;
int Laxt[maxn],Next[maxn],To[maxn],Len[maxn],q[maxn],cnt;
int dfn[maxn],low[maxn],times,scc[maxn],scc_cnt,head,K;
vector<int>G[maxn];
struct in{
int w,a,b;
in(){}
in(int ww,int aa,int bb):w(ww),a(aa),b(bb){}
friend bool operator <(in x,in y){ return x.w<y.w;}
};
void add(int u,int v,int w){
Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v; Len[cnt]=w;
}
void tarjan(int u,int fa)
{
dfn[u]=low[u]=++times;
q[++head]=u;
for(int i=Laxt[u];i;i=Next[i]){
if(To[i]==fa) continue;
if(!dfn[To[i]]) {
tarjan(To[i],u);
low[u]=min(low[u],low[To[i]]);
}
else low[u]=min(low[u],dfn[To[i]]);
}
if(low[u]==dfn[u]){
scc_cnt++;
while(true){
int x=q[head--];
scc[x]=scc_cnt;
if(x==u) break;
}
}
}
void merge(vector<int>&a,vector<int>b){
vector<int>res;
priority_queue<in>q;
for(int i=;i<b.size();i++)
q.push(in(a[]+b[i],,i));
while(res.size()<K&&!q.empty()){
in it=q.top(); q.pop();
res.push_back(it.w);
if(it.a+<a.size()){
it.a++; //当前数没了就把当前数的次大值拉进来,ok。
q.push(in(a[it.a]+b[it.b],it.a,it.b));
}
}
a=res;
}
int main()
{
int N,M,u,v,w,C=,sum; unsigned int res;
while(~scanf("%d%d",&N,&M)){
rep(i,,N) Laxt[i]=dfn[i]=scc[i]=low[i]=;
cnt=times=scc_cnt=head=; sum=; res=;
rep(i,,M) {
scanf("%d%d%d",&u,&v,&w);
add(u,v,w); add(v,u,w); sum+=w;
}
tarjan(,);
rep(i,,scc_cnt) G[i].clear();
rep(i,,N)
for(int j=Laxt[i];j;j=Next[j])
if(To[j]>i&&scc[i]==scc[To[j]])
G[scc[i]].push_back(Len[j]);
scanf("%d",&K);
vector<int>ans; ans.push_back();
rep(i,,scc_cnt){
if(G[i].size()>) merge(ans,G[i]);
}
for(int i=;i<ans.size();i++) res+=(i+)*(sum-ans[i]);
printf("Case #%d: %u\n",++C,res);
}
return ;
}

无向图tarjan:按边存。(想象一下有的点存在于多个环里)

void tarjan(int u,int fa)
{
dfn[u]=low[u]=++times; vis[u]=;
for(int i=Laxt[u];i;i=Next[i]){
int v=To[i];
if(!F[i]) continue;
F[i]=F[i^]=;
if(!vis[v]){
q[++head]=i;
tarjan(v,u);
low[u]=min(low[u],low[v]);
if(dfn[u]<=low[v])
{
int k,fcy=; scc_cnt++;
do
{
k=q[head--];
fcy++;
scc[k]=scc_cnt;
} while (k!=i);
if(fcy>) ans1++,ans2=(ll)ans2*(fcy+)%Mod;;
}
}
else if(dfn[v]<dfn[u]){
q[++head]=i;
low[u]=min(low[u],dfn[v]);
}
}
}

裸题K路归并:POJ2442,M个集合,每个集合大小为N,每个集合选一个数加起来,问前N小。

#include<bits/stdc++.h>
using namespace std;
const int maxn=;
struct in{
int x,pos;
in(){}
in(int xx,int pp):x(xx),pos(pp){}
friend bool operator <(in w,in v){return w.x>v.x;}
};
void merge(vector<int>&G,int N)
{
vector<int>res; priority_queue<in>q;
for(int i=,x;i<=N;i++){
scanf("%d",&x);
q.push(in(G[]+x,));
}
while(!q.empty()&&res.size()<N){
in w=q.top(); q.pop();
res.push_back(w.x);
if(w.pos+<G.size())
q.push(in(w.x+G[w.pos+]-G[w.pos],w.pos+));
}
G=res;
}
int main()
{
int T,M,N;
scanf("%d",&T);
while(T--){
scanf("%d%d",&M,&N);
vector<int>G ;
G.push_back();
for(int i=;i<=M;i++) merge(G,N);
for(int i=;i<N;i++) printf("%d ",G[i]);
puts("");
}
return ;
}

HDU - 6041:I Curse Myself(Tarjan求环&K路归并)的更多相关文章

  1. hdu 6041 I Curse Myself 无向图找环+优先队列

    I Curse Myself Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) ...

  2. HDU 6041 - I Curse Myself | 2017 Multi-University Training Contest 1

    和题解大致相同的思路 /* HDU 6041 - I Curse Myself [ 图论,找环,最大k和 ] | 2017 Multi-University Training Contest 1 题意 ...

  3. codevs4511信息传递(Tarjan求环)

    题目描述 有n个同学(编号为1到n)正在玩一个信息传递的游戏.在游戏里每人都有一个固定的信息传递对象,其中,编号为i的同学的信息传递对象是编号为Ti同学. 游戏开始时,每人都只知道自己的生日.之后每一 ...

  4. HDU 6041.I Curse Myself 无向仙人掌图

    I Curse Myself Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) ...

  5. HDU 6041 I Curse Myself(二分+搜索)

    [题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=6041 [题目大意] 给出一个仙人掌图,求第k小生成树 [题解] 首先找到仙人掌图上的环,现在的问题 ...

  6. AC日记——传话 codevs 1506 (tarjan求环)

    1506 传话  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 白银 Silver 题解       题目描述 Description 一个朋友网络,如果a认识b,那么如果a第 ...

  7. HDU 1827 Summer Holiday(tarjan求强连通分量+缩点构成新图+统计入度+一点贪心思)经典缩点入门题

    Summer Holiday Time Limit: 10000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)T ...

  8. HDU 5249 离线树状数组求第k大+离散化

    KPI Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...

  9. HDU 6041 I Curse Myself(点双联通加集合合并求前K大) 2017多校第一场

    题意: 给出一个仙人掌图,然后求他的前K小生成树. 思路: 先给出官方题解 由于图是一个仙人掌,所以显然对于图上的每一个环都需要从环上取出一条边删掉.所以问题就变为有 M 个集合,每个集合里面都有一堆 ...

随机推荐

  1. libvirt-qemu-虚拟机设备热插拔

    cpu热插拔 # virsh setvcpus $domain_name --count 4 --live (--config可写入配置文件永久保存) #前提条件和后续激活参考<libvirt- ...

  2. 【c++习题】【17/4/16】动态分配内存

    #include<iostream> #include<cstring> #define N 100 using namespace std; class String{ pu ...

  3. Linux:redhat6.5使用yum时提示需要注册问题解决方案

    Linux:redhat6.5使用yum时提示需要注册问题解决方案 一.问题 新安装了redhat6.5.安装后,登录系统,使用yum时候.提示: This system is not registe ...

  4. PHP memcache扩展模块安装

    安装php扩展模块memcache memcache 的工作就是在专门的机器的内存里维护一张巨大的hash表,来存储经常被读写的一些数组与文件,从而极大的提高网站的运行效率,减轻后端数据库的读写压力. ...

  5. 深入理解PHP之:Nginx 与 FPM 的工作机制

    网络上有很多关于如何配置 Nginx + FPM 的文章,但它们更多从操作的角度出发,告诉我们怎么做,但却没有告诉我们为什么要这么做,本文从 Nginx 与 FPM 的工作机制出发,探讨配置背后的原理 ...

  6. MySQL-Last_Errno: 1594

    故障现象  :MySQL slave所在机器自动重启,启动MySQL后,查看主从信息如下: Error_code: 1594   mysql> show slave status \G . ro ...

  7. 20145229吴姗姗web安全基础实践

    20145229吴姗姗web安全基础实践 基础与实践 基础问题 (1)SQL注入攻击原理,如何防御 SQL注入就是把SQL语句插入到之前已经定义好的语句中,作为网页中的比如用户名输入来达到攻击的目的, ...

  8. 《网络攻防》Web安全基础实践

    20145224陈颢文 <网络攻防>Web安全基础实践 基础问题回答 SQL注入攻击原理,如何防御: 部分程序员在编写代码的时候,没有对用户输入数据的合法性进行判断,黑客利用这个bug在数 ...

  9. spring security采用基于持久化 token 的方法实现的remember me功能

    采用该方法相较于简单加密方式安全一些.具体的原理见 http://wiki.jikexueyuan.com/project/spring-security/remember-me.html  一.建立 ...

  10. 关系型数据库的ACID规则

    1.A (Atomicity) 原子性 原子性很容易理解,也就是说事务里的所有操作要么全部做完,要么都不做,事务成功的条件是事务里的所有操作都成功,只要有一个操作失败,整个事务就失败,需要回滚. 比如 ...