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. 【Android 逆向】【攻防世界】黑客精神

    1. apk 安装到手机,提示输入注册码 2. jadx打开apk MainActivity.java @Override // android.app.Activity public void on ...

  2. 统信UOS系统开发笔记(四):从Qt源码编译安装之编译安装QtCreator4.11.2,并配置编译测试Demo

    前言   上一篇已经从Qt源码编译了Qt,那么Qt开发的IDE为QtCreator,本篇从源码编译安装QtCreator,并配置好构建套件,运行Demo并测试.   统信UOS系统版本   系统版本: ...

  3. 【转载】重装系统小贴士:ssh、vscode免密登录

    ssh安装 apt install openssh-server 然后到cd /etc/ssh下找sshd_config文件,打开把允许远程root登录的选项改为yes 重启ssh服务:/etc/in ...

  4. CT图像重建

    20世纪70年代中期,在医学领域出现了一种神奇装置,名为"计算机辅助 X 射线断层成像仪"(简称CAT或CT),它能够在不损伤病人的情况下,提供人体从头到脚各部位的断层X射线图像. ...

  5. 【Azure Compute Gallery】使用 Python 代码从 Azure Compute Gallery 复制 Image-Version

    问题描述 Azure Compute Gallery 可以帮助围绕 Azure 资源(例如映像和应用程序)生成结构和组织,并且支持全局复制. 如果想通过Python代码实现 Image-Version ...

  6. 3、zookeeper在java使用的API

    引入maven包 <dependency> <groupId>com.101tec</groupId> <artifactId>zkclient< ...

  7. Zabbix Agent item监控项讲解

    前言 agent与snmp是Zabbix两种重要的监控方式,这一期主要介绍Zabbix Agent item监控项..Zabbix agent分为主动代理.被动代理,配置item类型时,可以选择需要的 ...

  8. es索引数据复制并增加条件和修改目标数据值

    es操作同一个索引里数据的复制语法 复制数据: POST _reindex { "source": { "index": "source_index& ...

  9. Obsidian 0.15.9 知识笔记 使用说明

    我感觉这个软件是一个非常好用的软件,经过初步体验. 全局搜索快捷键 Ctrl + Shift + F 打开快速切换快捷键 Ctrl + O 添加标签 #测试标签 反向链接 Obsidian支持反向链接 ...

  10. Java | zuul 1.x 是如何实现请求转发的

    zuul 1.x 是如何实现请求转发的 文档写的再好,也不如源码写的好 源码地址: GitHub: https://github.com/Netflix/zuul Gitee: https://git ...