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. leetcode - 中序遍历

    给定一个二叉树的根节点 root ,返回 它的 中序 遍历 . 示例 1: 输入:root = [1,null,2,3] 输出:[1,3,2] 示例 2: 输入:root = [] 输出:[] 示例 ...

  2. 高效的PDF文字提取技术

    无论是行政法规.学术论文还是企业合同,PDF文档为我们提供了一种便捷.稳定的信息传递方式.然而,从PDF文件中提取文本信息对于数据分析.内容编辑等后续处理来说至关重要. PDF文本提取技术是一种可以从 ...

  3. 进击的 AI 生成,创造性的新世界!

    2022年,AI艺术生成文本生成图像的AI绘画生成器如雨后春笋般涌现,以一幅幅"不明觉厉"的AI作品进入大众视野.从2月Disco Diffusion爆火,仅两个月后OpenAI发 ...

  4. webservice之jersey简单实用

    前言 项目中更需要使用到webservice,具体的是使用jersey.那么首先需要了解jersey和webservice的关系,捋顺webservice框架的各种实现,通过查阅相关博客,我个人总结w ...

  5. 【Azure Developer】Java代码访问Key Vault Secret时候的认证问题,使用 DefaultAzureCredentialBuilder 或者 ClientSecretCredentialBuilder

    问题描述 使用Java SDK获取Key Vault Secret机密信息时,需要获取授权.通常是使用AAD的注册应用(Client ID, Tenant ID, Client Secret)来获取  ...

  6. 【Azure 应用服务】App Service 进入后台管理(Kudu)页面,因为文件过多而显示不全的问题

    问题描述 当App Service 应用发布到Azure上后,需要查看某一个日志文件时候,如果一个文件夹中的文件内容过多,则会出现错误消息提醒: Full error Message: There a ...

  7. Dungeon Master 题解

    这道题的题意简单来说:就是在3D迷宫里找出口,也就是三维地图,需要用到三维数组 由于本人写代码极易出错,所以在输入三维数组的时候修改了c(column,即列)的值,重复定义了没看到==,后面改成定义成 ...

  8. 【规范】看看人家Git提交描述,那叫一个规矩

    前言 缘由 没想到玩了多年git,竟然还有提交描述规范 事情起因: 在工作迭代过程中,偶然发现同组小帅哥Git提交描述总是和自己的不大一样,秉承好奇至上的我特意去研究了下.竟然发现提交了这么多年的Gi ...

  9. MySQL---面经

    如果想要对 MySQL 的索引树有更深入的了解,掘金的小册子:<MySQL 是怎样运行的> MySQL 是怎样运行的 以下是常见面试题 MySQL日志 MySQL日志系统 redo_log ...

  10. logon scripts后门

    Windows登录脚本,当用户登录时触发,Logon Scripts能够优先于杀毒软件执行,绕过杀毒软件对敏感操作的拦截 注册表位置:HKEY_CURRENT_USER\Environment 在命令 ...