JZOJ 3501 消息传递

洛谷2018加强版

题目

有一藤蔓和一棵\(n(n\leq 2*10^5)\)个点的无根树,可以用1单位时间YC把藤蔓种在树的任意位置

然后只要任意位置有藤蔓,它就会在一个单位时间内按照YC的意愿到相邻的一个位置延长

YC想考考你最短什么时候藤蔓会覆盖整一棵树,由于YC出类拔萃,

他还想问你他把藤蔓种在哪里能使时间最短并输出全部符合题意的节点


分析

考虑树形dp,二次扫描换根法,假设以某个放置位置为根

先以1为根,设\(f[i]\)表示藤蔓从\(i\)被覆盖那一刻开始覆盖以i为根的子树所需要的最短时间,

那么\(f\)越大肯定越想早延长,所以按照子节点的\(f\)降序排序

那么\(f[i]=max\{f[son]+order_{son}\}\)

不换根可以做到\(n^2log_2n\)的时间复杂度以通过弱化版

换根就要考虑父节点对以子节点为根的树答案影响

如果这个点不是1,就可以不用考虑1的父节点对换根答案影响,否则把它加进刚刚的候选数组,因为现在要换根下传\(f\)

还是一样按照\(f\)大到小排序,然后用前缀\(max\)和后缀\(max\),然后用它更新子节点,顺便还能求答案(最大值就是答案)

然后在dp的时候这里的根\(f[x]\)表示的实际意义是\(x\)在以\(x\)的子节点为根的树的\(f\),然而1并没有父节点,所以就是刚刚提到不用加进去排序

然后\(suf\)为什么要减1就是因为原来的\(f[x]\)是不用计算答案的,所以后面整体前移一位

时间复杂度\(O(nlog_2n)\),至于为什么代码看得有点古怪,大概是\(\text{STL::vector}\)以0开头


代码

#include <cstdio>
#include <cctype>
#include <algorithm>
#include <vector>
#define rr register
using namespace std;
const int N=200011;
vector<int>pt[N];
int f[N],pre[N],suf[N],n,dp[N],ans;
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
bool cmp(int x,int y){return f[x]>f[y];}
inline void dfs1(int x){
for (rr int i=0;i<pt[x].size();++i) dfs1(pt[x][i]);
sort(pt[x].begin(),pt[x].end(),cmp);
for (rr int i=0;i<pt[x].size();++i) f[x]=max(f[x],f[pt[x][i]]+i+1);
}
inline void dfs2(int x){
if (x>1){
pt[x].push_back(x);
for (rr int i=pt[x].size()-2;~i;--i){
rr int t1=pt[x][i],t2=pt[x][i+1];
if (f[t1]<f[t2]) t1^=t2,t2^=t1,t1^=t2;
pt[x][i]=t1,pt[x][i+1]=t2;
}
}
pre[0]=suf[pt[x].size()+1]=0;
for (rr int i=1;i<=pt[x].size();++i) pre[i]=max(pre[i-1],f[pt[x][i-1]]+i);
for (rr int i=pt[x].size();i;--i) suf[i]=max(suf[i+1],f[pt[x][i-1]]+i);
dp[x]=pre[pt[x].size()],ans=min(ans,dp[x]);
for (rr int i=1;i<=pt[x].size();++i) f[pt[x][i-1]]=max(pre[i-1],suf[i+1]-1);
for (rr int i=0;i<pt[x].size();++i)
if (pt[x][i]!=x) dfs2(pt[x][i]);
}
signed main(){
n=iut();
for (rr int i=2;i<=n;++i)
pt[iut()].push_back(i);
ans=2e9,dfs1(1),dfs2(1);
print(ans+1),putchar(10);
for (rr int i=1;i<=n;++i)
if (ans==dp[i]) print(i),putchar(32);
return 0;
}

简单写就能跳过之题目

JZOJ 3500 物语

题目

一个\(n\)个点\(m-1\)条边的无向图,还有一条隐藏边,这条边只知道两个端点\(X,Y\)和\(Q\)次询问给出的长度\(W\),每次询问从点1到点\(n\)的最短路,如果到达不了就输出“+Inf”


分析

因为无向图,所以正反相同,从1跑一次单源最短路,记作\(dis[0][\_]\),再从\(n\)跑一次单源最短路,记作\(dis[1][\_]\)

那么答案为三种情况的其中1种。

1:不用经过这条边

2:1到\(x\),\(x\)到\(y\),\(y\)到\(n\)

3:1到\(y\),\(y\)到\(x\),\(x\)到\(n\)

然后跑\(\text{SPFA}\)被卡了,所以就写了\(\text{Dijkstra+Heap优化}\)


代码

#include <cstdio>
#include <cctype>
#include <queue>
#define rr register
using namespace std;
const int N=200011; typedef long long lll;
struct node{int y,w,next;}e[N<<3]; pair<lll,int>heap[N];
lll dis[2][N]; int n,k=1,Q,m,ls[N],cnt;
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(lll ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline void Push(pair<lll,int>w){
heap[++cnt]=w;
rr int x=cnt;
while (x>1){
if (heap[x>>1]>heap[x])
swap(heap[x>>1],heap[x]),x>>=1;
else return;
}
}
inline void Pop(){
heap[1]=heap[cnt--];
rr int x=1;
while ((x<<1)<=cnt){
rr int y=x<<1;
if (y<cnt&&heap[y+1]<heap[y]) ++y;
if (heap[y]<heap[x]) swap(heap[y],heap[x]),x=y;
else return;
}
}
inline void dijk(int sta,int poi){
for (rr int i=1;i<=n;++i) dis[poi][i]=1e16;
heap[++cnt]=make_pair(0,sta),dis[poi][sta]=0;
while (cnt){
rr lll t=heap[1].first; rr int x=heap[1].second;
Pop(); if (dis[poi][x]!=t) continue;
for (rr int i=ls[x];i;i=e[i].next)
if (dis[poi][e[i].y]>dis[poi][x]+e[i].w){
dis[poi][e[i].y]=dis[poi][x]+e[i].w;
Push(make_pair(dis[poi][e[i].y],e[i].y));
}
}
}
signed main(){
n=iut(); m=iut(); Q=iut();
for (rr int i=1;i<m;++i){
rr int x=iut(),y=iut(),w=iut();
e[++k]=(node){y,w,ls[x]},ls[x]=k;
e[++k]=(node){x,w,ls[y]},ls[y]=k;
}
rr int X=iut(),Y=iut();
dijk(1,0),dijk(n,1);
for (rr int i=1;i<=Q;++i,putchar(10)){
rr int W=iut(); rr lll now=dis[0][n];
now=min(now,dis[0][X]+W+dis[1][Y]);
now=min(now,dis[0][Y]+W+dis[1][X]);
if (now>=1e16) printf("+Inf");
else print(now);
}
return 0;
}

JZOJ 3757 洛谷 2354 [NOI 2014] 随机数产生器

题目

按照题意构造一个\(1\sim n*m\)的排列,然后把它依次填入一个二维数组,

接着从左上角走到右下角只能向右或向下走,通过这种方式可以得到一个长为\(n+m-1\)的序列,再将这个序列升序排序,问这个序列字典序最小的方案


分析

首先贪心,想到的是1肯定在第一个,接着1左下角(不包括正左边和正下方)、右上角(同理)都不能选,再选第二小,以此类推,

那我能用二维数据结构维护,但是256MB貌似会MLE

而且二维树状数组最值区间修改好像很难,那只能放弃这种想法,那得用时间换空间

那就暴力维护吧,我可以用\(Lmax,Rmin\)表示某一行左边的最右可选和右边的最左可选(因为选择区间肯定在中间且都能被选)

如果该数的位置满足,那么再用这个位置暴力更新\(Lmax,Rmin\),并输出这个数,时间复杂度\(O((n+m)n)\)


代码

#include <cstdio>
#include <cctype>
#define rr register
using namespace std;
const int N=5000;
int x0,A,B,C,D,n,m,ti,cnt,a[N*N],rk[N*N],lmax[N],rmin[N];
inline signed iut(){
rr int ans=0; rr char c=getchar();
while (!isdigit(c)) c=getchar();
while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
return ans;
}
inline void print(int ans){
if (ans>9) print(ans/10);
putchar(ans%10+48);
}
inline signed min(int a,int b){return a<b?a:b;}
inline signed max(int a,int b){return a>b?a:b;}
inline void swap(int &a,int &b){rr int t=a; a=b,b=t;}
inline signed mo(int x,int y){return x+y>=D?x+y-D:x+y;}
signed main(){
x0=iut(),A=iut(),B=iut(),C=iut(),
D=iut(),n=iut(),m=iut(),ti=n*m;
for (rr int i=0;i<ti;++i) a[i]=i;
for (rr int i=1;i<=ti;++i){
x0=mo(1ll*x0*mo(1ll*A*x0%D,B)%D,C);
swap(a[x0%i],a[i-1]);
}
for (rr int Q=iut();Q;--Q) swap(a[iut()-1],a[iut()-1]);
for (rr int i=0;i<ti;++i) rk[a[i]]=i;
for (rr int i=0;i<n;++i) rmin[i]=m-1;
for (rr int p=0;p<n*m;++p){
rr int x=rk[p]/m,y=rk[p]%m;
if (lmax[x]<=y&&y<=rmin[x]){
print(p+1),putchar(32),++cnt;
if (cnt==n+m-1) return 0;
for (rr int i=0;i<x;++i) rmin[i]=min(rmin[i],y);
for (rr int i=x+1;i<n;++i) lmax[i]=max(lmax[i],y);
}
}
}

#树形dp,二次扫描换根法#JZOJ 3501 消息传递 with others的更多相关文章

  1. $Poj3585\ Accumulation Degree$ 树形$DP/$二次扫描与换根法

    Poj Description 有一个树形的水系,由n-1条河道与n个交叉点组成.每条河道有一个容量,联结x与y的河道容量记为c(x,y),河道的单位时间水量不能超过它的容量.有一个结点是整个水系的发 ...

  2. poj3585 树形dp 二次扫描,换根法模板题

    #include<iostream> #include<cstring> #include<cstdio> #include<vector> using ...

  3. 题解 poj3585 Accumulation Degree (树形dp)(二次扫描和换根法)

    写一篇题解,以纪念调了一个小时的经历(就是因为边的数组没有乘2 phhhh QAQ) 题目 题目大意:找一个点使得从这个点出发作为源点,流出的流量最大,输出这个最大的流量. 以这道题来介绍二次扫描和换 ...

  4. poj 3585 Accumulation Degree(二次扫描和换根法)

    Accumulation Degree 大致题意:有一棵流量树,它的每一条边都有一个正流量,树上所有度数为一的节点都是出口,相应的树上每一个节点都有一个权值,它表示从这个节点向其他出口可以输送的最大总 ...

  5. poj3585树最大流——换根法

    题目:http://poj.org/problem?id=3585 二次扫描与换根法,一次dfs求出以某个节点为根的相关值,再dfs遍历一遍树,根据之前的值换根取最大值为答案. 代码如下: #incl ...

  6. cf219d 基础换根法

    /*树形dp换根法*/ #include<bits/stdc++.h> using namespace std; #define maxn 200005 ]; int root,n,s,t ...

  7. POJ - 3585 树上最大流 换根法

    题意:给出一棵树,边上有容量限制,求以任一点作为根和源点,叶子作为汇点的最大流的最大值 首先上网络流等于找死 树形DP可以\(O(n)\)求出以某点\(u\)为根的最大流,只需设\(f[u]=\sum ...

  8. UVA 10859 Placing Lamppost 树形DP+二目标最优解的求解方案

    题意:给定一个无向,无环,无多重边,要求找出最少的若干点,使得,每条边之中至少有一个点上有街灯.在满足上述条件的时候将还需要满足让两个点被选择的边的数量尽量多. 题解: 对于如何求解最小的节点数目这点 ...

  9. 【POJ3585】Accumulation Degree 二次扫描与换根法

    简单来说,这是一道树形结构上的最大流问题. 朴素的解法是可以以每个节点为源点,单独进行一次dp,时间复杂度是\(O(n^2)\) 但是在朴素求解的过程中,相当于每次都求解了一次整棵树的信息,会做了不少 ...

  10. hdu2196 Computer【树形DP】【换根法】

    Computer Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Su ...

随机推荐

  1. 使用3-hexo主题时无法正常渲染html代码

    问题描述 在hexo框架中使用3-hexo主题时,会遇到这样一个问题:在markdown中嵌入html代码,这些嵌入的html代码无法正常显示. 原因分析 在使用3-hexo主题时,默认使用主题自带的 ...

  2. offline RL | 读读 Decision Transformer

    论文标题:Decision Transformer: Reinforcement Learning via Sequence Modeling,NeurIPS 2021,6 6 7 9 poster( ...

  3. HAProxy端口资源耗尽的解决办法

    项目背景 系统使用HAProxy为mq和部分应用的负载均衡服务.近期,瞬时流量过大,导致出现连锁反应,HA开始波动. HAProxy版本:1.6.3 问题分析 心跳检测大量失败,项目状态极不稳定.观察 ...

  4. 【Azure Developer】调用Microsoft Graph API获取Authorization Token,使用的认证主体为 Azure中的Managed Identity(托管标识)

    问题描述 在常规情况下,如果要从Azure中获取Authorization Token,需要在Azure AAD中注册一个应用主体,通过Client ID + Client Secret生成Token ...

  5. 为Oracle链接服务器使用分布式事务

    1 现象 在SQL Server中创建指向Oracle的链接服务器,SQL语句在事务中向链接服务器插入数据.返回链接服务器无法启动分布式事务的报错. 2 解决 在Windows平台下,SQL Serv ...

  6. Toyota Programming Contest 2024#2(AtCoder Beginner Contest 341)D - Only one of two(数论、二分)

    目录 链接 题面 题意 题解 代码 总结 链接 D - Only one of two 题面 题意 求第\(k\)个只能被\(N\)或\(M\)整除的数 题解 \([1,x]\)中的能被\(n\)整除 ...

  7. CPNtools协议建模安全分析---实例库所标记(四)

    1.我们经常使用弧上单个变量表达式来过滤数据类型,如果是多个类型的变量可以嵌套写 像上面的的 库所标记的数值 1·(2,5,"a")++        那么弧表达式会根据要求来过滤 ...

  8. sql99等值&&非等值查询

    1 #二.sql99语法 2 /* 3 语法 4 SELECT 查询列表 5 FROM 表1 别名 [连接类型] 6 JOIN 表2 别名 7 on 连接条件 8 [where 筛选条件] 9 [gr ...

  9. [.Net]使用Soa库+Abp搭建微服务项目框架(四):动态代理和RPC

    ​上一章我们完成了小项目的面向服务体系改造,你或许一直在思考一个问题.为什么要将业务独立成微服务? 微服务原理 以一个健康医疗系统为例, 这个系统包含了用户模块,问卷的发放与填写,图表显示,报表生成与 ...

  10. 玩转Vue3之shallowRef和shallowReactive

    前言 Vue3 作为一款现代的 JavaScript 框架,引入了许多新的特性和改进,其中包括 shallowRef 和 shallowReactive.这两个功能在Vue 3中提供了更加灵活和高效的 ...