门户营销型网站搭建,如何看网站是谁做的,织梦 别人 网站 模板,客源网站解析
纯纯的人类智慧题。
关键性质#xff1a;vvv 可以在计算 f(u,G)f(u,G)f(u,G) 时产生贡献#xff0c;当且仅当 GGG 中 u,vu,vu,v 之间可以通过 [v,n][v,n][v,n] 的点互相到达。 充分性较为显然#xff0c;编号更大的点不会比 vvv 先删去#xff0c;所以必然在 vvv 时…解析
纯纯的人类智慧题。
关键性质vvv 可以在计算 f(u,G)f(u,G)f(u,G) 时产生贡献当且仅当 GGG 中 u,vu,vu,v 之间可以通过 [v,n][v,n][v,n] 的点互相到达。 充分性较为显然编号更大的点不会比 vvv 先删去所以必然在 vvv 时刻依然存在。 必要性证明假设 vvv 时刻 u→vu\to vu→v 的路径上存在一个 x∈[1,v)x\in [1,v)x∈[1,v)在 xxx 时刻图的联通性不弱于 vvv 时刻因而必然也有 u→xu\to xu→x 可达且由于 x→v,v→ux\to v,v\to ux→v,v→u 皆可达也就有 x→ux\to ux→u 可达xxx 应当被删去矛盾。
接下来的任务就是如何维护这个东西。
floyd
对于点编号属于 [v,n][v,n][v,n] 这样的限制不难想到 floyd。但是直接跑无法通过 n1000n1000n1000。 然后拿大样例试了试发现写成
for(int kn;k1;k--){for(int i1;ik;i){for(int ji;jn;j){k - update(i,j)}}}答案依然是对的并且能跑过1000了。 然后就完事了。
我们当然要想一想为什么这样是对的。 这么转移必然出问题的就是两边的点编号均大于 kkk 的情况。 如图中的 p,qp,qp,q 高度表示点编号的相对大小
那么我们现在就要证明 若 (x,y)(x,y)(x,y) 路径上没有经过 [1,min(x,y))[1,\min(x,y))[1,min(x,y)) 的点就必然可以正确转移。 假设枚举到中转点 kkk 之前的路径都符合这个性质。 对于当前枚举的中转点 kkk注意到我们需要求出的合法路径必然至少有一个端点是小于 kkk 的。 那么就必然能在 kkk 的某一侧找到第一个编号小于 kkk 的点 xxxk→xk\to xk→x 这段路径使用 (k,n](k,n](k,n] 的点中转不会出现现在 p,qp,qp,q 这样的窘境所以 f(k,x)f(k,x)f(k,x) 当前是对的。 那么 xxx 就可以通过 kkk 连接起另一侧的 ppp 得到正确的 f(p,x)f(p,x)f(p,x)。 如果 (u,p)(u,p)(u,p) 之间有 k′kk′ 这样的点导致 f(u,p)f(u,p)f(u,p) 不对怎么办把(u,p)(u,p)(u,p) 最小的点 k′kk′ 当成 ppp 的角色来考虑刚才的证明就还是对的。
bfs
本题看题解还有通过 bfs 求对每个 vvv 考虑在每张图中能对多少 uuu 产生贡献的方法来做的每次 bfs 用到一条边就直接删去从而保证复杂度为 O(nm)O(nm)O(nm)也挺妙的。
代码
#includebits/stdc.h
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug(OK\n)
using namespace std;const int N1050;
const int M2e5100;
const int inf1e9;
const int mod19921228;inline ll read(){ll x(0),f(1);char cgetchar();while(!isdigit(c)) {if(c-)f-1;cgetchar();}while(isdigit(c)) {x(x1)(x3)c-0;cgetchar();}return x*f;
}int n,m;
int f[N][N];
ll sum[M];signed main() {
#ifndef ONLINE_JUDGEfreopen(a.in,r,stdin);freopen(a.out,w,stdout);
#endif//memset(f,0x3f,sizeof(f));nread();mread();for(int i1;im;i){int xread(),yread();f[x][y]i;}for(int i1;in;i) f[i][i]m1;for(int kn;k1;k--){for(int ik;in;i) sum[min(f[i][k],f[k][i])];for(int i1;ik;i){//if(!f[i][k]!f[k][i]) continue;for(int ji;jn;j){f[i][j]max(f[i][j],min(f[i][k],f[k][j]));f[j][i]max(f[j][i],min(f[j][k],f[k][i]));}}}for(int im;i1;i--) sum[i]sum[i1];for(int i1;im1;i) printf(%lld ,sum[i]);return 0;
}
/*
*/