IOI 2011 Tropical Gardens
给定一个N个点M条边的无向图,每条边有一条边权,保证没有孤立点
进行Q次询问,每一次询问给定一个 K Q K_Q KQ,求符合如下条件的路径的数目
- 以任意节点为起点
- 假设沿着边E’进入节点X,与点X相连的边记为 {E}
- 优先选择 {E} 中边权最小的边
- 假如边权最小的边是E’
- 如果|E|为1,选择E‘
- 否则选择边权第二小的边
- 经过恰好K条边之后到达给定节点P
思路:
首先,给定起点和步数后,路径显然固定
看到分类讨论的条件可以考虑拆点
X表示走最小边,X’表示走次小边
原题由于是交互题,边权已经排序,建图只需要遍历每一条边记录与每一个点相连的最小边和次小边,最后处理只有一条出边的节点,建立有向图G,枚举每个点为起点的路径,检查重点是否为P,并统计。时间复杂度为O(M + NKQ)
现在可以过Subtask 1了:
N <= 1000, M <= 10000, Q = 1, K <= 100
(这就有49分了)
然而Subtask 3 中K达到了可怖的 1 0 9 10^9 109,显然我们需要消除K
考虑题目给定的终点P:由于终点是固定的,我们可以将G反向,构成新图 G T G^T GT
由于路径是固定的,G中每一个点至多有一条出边,因此 G T G^T GT中每一个点至多有一条入边
这也就说明,从P点开始DFS,假设遇到环,那么这个环一定包含P
读者真的自证不难
我们在DFS过程中记录每个点的dist(初始为 inf \inf inf),记为 F i F_i Fi,将环长记为C(假如没有环则为 inf \inf inf)
那么以一个点为起点经过恰好K条边到达点P的充要条件是
存在一个自然数λ,使得K = F i F_i Fi + λC
复杂度为O(M + NQ),可以得到满分
一定注意所有编号从0开始!!!!!
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#include<iostream>
#include "garden.h"
#include "gardenlib.h"
//这是一道交互题
using namespace std;
int mmax[150007], sec[150007], dist[300007][2], head[300007], eid, c[2], st;
struct edge {
int to, next;
}e[300007];
inline void insert(register int a, register int b) {
e[++eid].to = b; e[eid].next = head[a]; head[a] = eid;
}
inline void dfs1(register int u) {
//printf("%d\n", u);
for(register int i = head[u]; i; i = e[i].next) {
int v = e[i].to;
if(dist[v][0] != 0x3f3f3f3f) {
//if(v != st << 1) {cerr << "Abort\n"; exit(0);}
c[0] = dist[u][0] + 1 - dist[v][0];
continue;
}
dist[v][0] = dist[u][0] + 1;
dfs1(v);
}
}
inline void dfs2(register int u) {
for(register int i = head[u]; i; i = e[i].next) {
int v = e[i].to;
if