题目描述

最近,木木中学要举行一年一度的辩论赛了,我们活泼开朗乐观向上不寂寞不生病不挂科天天回家吃饭的新时代好少年--飞飞,自然是热情参与咯!辩论嘛,就有正方和反方两个组,这是一个传统项目,所以,包括飞飞,木木中学的每一个学生都会加入2个组中的一个,不会有人打酱油的(如果有人打酱油,那么飞飞会义无反顾义不容辞的上前用一翻惊天动地的演说打消他打酱油的念头的)。自然啦,作为有思想有文化能言善辩的好少年,飞飞,其实加入哪个组,从技术角度分析真是无所谓的,不过呢,从另外一些角度来看,就复杂的多了……比如,飞飞是个很不喜欢八卦的正义青年,所以啊,飞飞很不想和年级最PP的女生青菜分在一个组,因为会产生八卦的--为什么会有八卦?首先是他们比较熟(比较熟就会有八卦吗?无限yy中……),最重要的就是因为飞飞是大帅哥啊!人长得帅,有时候真是挺麻烦的,尤其飞飞还如此低调……再比如,飞飞也不想和小邱分在一个组--虽然他们不认识,但是,飞飞听说小邱很懒还很暴力,飞飞不喜欢暴力……当然了,不论如何的分组行动,都会产生一些代价的,比如两个好朋友分在了不同的组,那肯定不是很高兴了。飞飞知道,学校里有M对同学是相互认识的,每对认识的同学间,都有一个要好程度C,自然的,关系越好,要好程度越高,也越不愿意分开。对于一个分组方案,必然会使得有某些认识的同学分开,飞飞认为,一个分组方案的代价就是最不愿意分开的那两个同学之间的要好程度。飞飞在想,和青菜MM分在不同的组最小代价是多少呢?和小邱同学分在不同的组最小代价是多少呢?如果……还要将青菜MM和小邱分在不同的组最小代价是多少呢?……好麻烦啊,飞飞越想越乱,于是来找你帮忙了。一些说明:木木中学有N个学生,木木中学是一所优秀的中学,学生们都是开朗外向的,所以一个学校里任意两个学生间接或者直接肯定认识。显然任意一个辩论组都至少得有一个人。为了方便,我们把木木中学的学生用1到N编号,飞飞有Q个问题,每个问题的形式都是这样的:将编号为a的学生与编号为b的学生分在不同组中,最少的代价是多少呢?关于这道题目本身,只是想检验你能不能帮飞飞,所以你并不需要--具体回答每个问题,只需要最后输出每个问题答案的乘积除以P的余数就可以了。

输入格式

输入文件中的第一行为四个正整数N,M,Q,P。

第二行至第M+1行,每行有三个正整数a,b,c,表示编号为a的同学和编号为b的同学认识,并且要好程度是c。

保证a和b是不会相同的,也不会有多行描述相同两个学生之间的关系。

第M+2行至第M+Q+1行,每行有两个正整数a,b,表示飞飞的一个问题,这里保证a和b是不同的。

N<5000,M<10000,Q<1000,C<1000000,P<1000000。

输出格式

输出文件中仅一行为一个整数,所有问题答案的乘积除以P的余数。


题目翻译过来就是:对于每个询问的a,b,要求将原图分成两个不相连的连通块,并且a,b不在同一个连通块中,答案就是原图中两个连通块之间相连的边的边权最大值。

进一步,我们可以把题目理解为:删掉一些边使得a,b不连通,删去边的最大值就是答案。

但是删边的操作太复杂,不如考虑倒过来变成加边的操作。

显然删边时我们需要从小到大删,那么加边时我们就从大到小加。然后当加上一条边使得a,b连通时,此时加的边的边权就是答案,因为比这条边更大的边不足以使a,b连通,那么我们可以把它们放入连通块中。而此时剩下的边不会大于当前边,无论删哪些边答案都是当前边的边权。

考虑实现方式:

先对边从大到小排序。加边可以用并查集实现,每次加边之后枚举每个询问,看是否未被回答过并且现在连通了,并记录答案。忽略掉并查集的复杂度,那么时间复杂度就是O(MlogM+MQ),会T掉。那么考虑优化:

我们的原本的策略是回答一个询问后打上标记,当再次循环到这个位置时就跳过。那么当询问回答得差不多时就会产生很大的空转。那么我们的优化方法有两个:

1.Dancing Links,用链表的形式存储询问,回答了当前询问时就从链表删掉这个询问。

2.队列优化。将未回答的询问加入队列,回答之后将询问出队。

那么用了上述优化之后可以把复杂度降为O(MlogM+KQ),K是一个比较小的常数。


但上面的离线做法显然不尽人意,原因是处理问题时不能及时调动存储的询问。所以我们可以考虑在线做法。

类比着离线做法,用并查集从大到小加边可以看作是求原图的最大生成树,加到询问的两个点连通的边可以看作是询问的两点在最大生成树的路径上的最小边。所以我们在线的做法就是:

求出最大生成树,然后对于每个询问,求出两点在树上路径上的最小边,这个可以用倍增求。那么复杂度就是:O(MlogM+(N+Q)logN)

放出在线做法的代码:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define maxn 5001
#define maxm 10001
using namespace std; int n,m,q,p,ans=1;
inline int read(){
register int x(0),f(1); register char c(getchar());
while(c<'0'||'9'<c){ if(c=='-') f=-1; c=getchar(); }
while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return x*f;
} struct edge{
int to,dis,next;
edge(){}
edge(const int &_to,const int &_dis,const int &_next){ to=_to,dis=_dis,next=_next; }
}e[maxn<<1];
int head[maxn],k;
inline void add(const int &u,const int &v,const int &w){ e[k]=edge(v,w,head[u]),head[u]=k++; } struct birm{
int u,v,w;
bool operator<(const birm &b)const{ return w>b.w; }
}b[maxm];
int fa[maxn],tot;
int get(int x){ return x==fa[x]?x:fa[x]=get(fa[x]); }
inline void kruskal(){
sort(b+1,b+1+m);
for(register int i=1;i<=n;i++) fa[i]=i;
for(register int i=1;i<=m;i++){
int u=b[i].u,v=b[i].v,w=b[i].w;
if(get(u)==get(v)) continue;
fa[get(u)]=get(v),tot+=w;
add(u,v,w),add(v,u,w);
}
} int minedge[maxn][20],f[maxn][20],dep[maxn],maxdep;
void dfs_getmax(int u,int pre){
for(register int i=head[u];~i;i=e[i].next){
int v=e[i].to;
if(v==pre) continue;
f[v][0]=u,minedge[v][0]=e[i].dis,dep[v]=dep[u]+1;
for(register int j=1;j<=maxdep;j++) f[v][j]=f[f[v][j-1]][j-1],minedge[v][j]=min(minedge[v][j-1],minedge[f[v][j-1]][j-1]);
dfs_getmax(v,u);
}
}
inline int getmin(int u,int v){
int ans=0x3f3f3f3f;
if(dep[u]>dep[v]) swap(u,v);
for(register int i=maxdep;i>=0;i--) if(dep[f[v][i]]>=dep[u]) ans=min(ans,minedge[v][i]),v=f[v][i];
if(u==v) return ans;
for(register int i=maxdep;i>=0;i--) if(f[u][i]!=f[v][i]) ans=min(ans,min(minedge[u][i],minedge[v][i])),u=f[u][i],v=f[v][i];
return min(ans,min(minedge[u][0],minedge[v][0]));
} int main(){
memset(head,-1,sizeof head),memset(minedge,0x3f,sizeof minedge);
n=read(),m=read(),q=read(),p=read(),maxdep=(int)log(n)/log(2)+1;
for(register int i=1;i<=m;i++) b[i].u=read(),b[i].v=read(),b[i].w=read();
kruskal(),dfs_getmax(1,-1);
for(register int i=1;i<=q;i++){
int u=read(),v=read();
ans=(1ll*ans*getmin(u,v))%p;
}
printf("%d\n",ans);
return 0;
}

[noip模拟]分组行动的更多相关文章

  1. 2019.8.3 [HZOI]NOIP模拟测试12 C. 分组

    2019.8.3 [HZOI]NOIP模拟测试12 C. 分组 全场比赛题解:https://pan.baidu.com/s/1eSAMuXk 刚看这题觉得很难,于是数据点分治 k只有1和2两种,分别 ...

  2. NOIP模拟赛20161022

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

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

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

  4. NOIP模拟赛 by hzwer

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

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

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

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

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

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

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

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

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

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

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

随机推荐

  1. Python SQLALchemy框架

    SQLALchemy SQLALchemy是Python中的一款优秀的ORM框架,它可以作用于任何第三方Web框架,如flask,tornado等框架. SQLALchemy相较于DjangoORM来 ...

  2. html 10-HTML基础回顾

    10-HTML基础回顾 #本文主要内容 html 的常见元素 html 元素的分类 html 元素的嵌套关系 html 元素的默认样式和 CSS Reset html 常见面试题 #html 的常见元 ...

  3. Sqlmap 学习笔记1:sqlmap参数

    SQLMP参数分析 1 目录 1.Target Options 2.Requests Options 3.Injection Options 4.Detection Options 5.Techniq ...

  4. Linux课程知识点总结(一)

    Linux课程知识点总结(一) 一.Linux系统的简介 1.1 什么是Linux Linux是一个免费的多用户.多任务的操作系统,其运行方式.功能和Unix系统很相似,但Linux系统的稳定性.安全 ...

  5. python之代码重构

    在撸码过程中,总有很多代码需要重构,码一个问候用户的小例子,加深对代码重构的印象. 原始代码: 1 import json 2 3 filename = 'username.json' #定义文件名 ...

  6. 使用IDE练习插件【廖雪峰】

    使用廖雪峰大神的插件,安装过程中,一直出现问题,然后在他的Java教程下面看大家的评论也有点晕了(很多人说的是jar包,结果其实是下的依旧是zip包) 最终解决方法: 将zip包解压到同名文件夹中,再 ...

  7. MALL的学习笔记启动计划

    基本网络文档:http://www.macrozheng.com/#/ 电子书: Spring: <Spring实战(第4版)> Springboot: <Spring Boot实战 ...

  8. java斐波纳契数列

    //斐波纳契数列,又称黄金分割数列,指的是这样一个数列:1.1.2.3.5.8.13.21.-- 这个数列从第三项开始,每一项都等于前两项之和. public class DiGui { public ...

  9. 根据来源编号对明细进行分组 跟库存做对比 用到的技术 list根据某个字段分组 Double Long 比较大小

    public R startProcess(@RequestBody ShouldCredentialPayable bean) { System.out.println("应付贷项参数be ...

  10. 在搜索引擎中输入汉字就可以解析到对应的域名,请问如何用LoadRunner进行测试。

    建立测试计划,确定测试标准和测试范围 设计典型场景的测试用例,覆盖常用业务流程和不常用的业务流程等 根据测试用例,开发自动测试脚本和场景: 录制测试脚本:新建一个脚本(Web/HTML协议):点 ...