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. kafka学习笔记02-kafka消息存储

    kafka消息存储 broker.topic.partition kafka 的数据分布是一个 3 级结构,依次为 broker.topic.partition. 也可以理解为数据库的分库分表,然后还 ...

  2. Python嵌套绘图并为条形图添加自定义标注

    论文绘图时经常需要多图嵌套,正好最近绘图用到了,记录一下使用Python实现多图嵌套的过程. 首先,实现 Seaborn 分别绘制折线图和柱状图. '''绘制折线图''' import seaborn ...

  3. 进度条模块之tqdm

    导入模块 from tqdm import tqdm import time ''' desc 描述 ncols 进度条总长度 可修改 range(1000) 封装迭代器 ''' for i in t ...

  4. 最简单的python判断是否是回文

    def isNumberPalindrome(number): if isinstance(number, int): number = str(number) return number == nu ...

  5. Elasticsearch-Mapping(映射)

    Elasticsearch-Mapping(映射) Mapping是用来定义一个文档(document),以及它所包含的属性(field)是如何存储和 索引的. 哪些字符串属性应该被看做全文本属性(f ...

  6. 在写dockerfile时替换国内源

    众所周知,Debian是linux发行版中官方源最难用的一个,这个傻逼源让我再构建docker镜像时卡了很久. ​ 那么能不能替换构建dockerfile时使用的源呢?显然是可以的 ​ 在与Docke ...

  7. 文心一言 VS 讯飞星火 VS chatgpt (208)-- 算法导论15.4 5题

    五.设计一个 O($n^2$) 时间的算法,求一个 n 个数的序列的最长单调递增子序列.要写代码的时候,请用go语言. 文心一言,抛panic: 在 Go 语言中设计一个 O(n^2) 时间复杂度的算 ...

  8. C++ //vector容器嵌套容器

    1 //vector容器嵌套容器 2 #include <iostream> 3 #include <string> 4 #include<fstream> 5 # ...

  9. 2023山东省“技能兴鲁”职业技能大赛-学生组初赛wp

    PWN pwn1 c++ pwn,cin 直接相当于 gets 了,程序有后门,保护基本没开,在 change 的最后一个输入点改掉返回地址为后门地址即可 from pwn import * cont ...

  10. ADS1299芯片datasheet 重点解析

    一 START和DRDY的关系 start必须要至少提前拉高2个时钟,才会产生DRDY信号,这个非常关键,也是重心所在.很多遗漏的就不会有DRDY信号出来了. 二 START和DRDY的时序图 sta ...