当前位置: 首页 > wzjs >正文

开发网络新技术的平台搜索引擎排名优化方案

开发网络新技术的平台,搜索引擎排名优化方案,DW做的网站加载慢,idea网站开发洛谷P3128 [USACO15DEC] Max Flow P 洛谷题目传送门 题目描述 Farmer John 在他的谷仓中安装了 N − 1 N-1 N−1 条管道,用于在 N N N 个牛棚之间运输牛奶( 2 ≤ N ≤ 50 , 000 2 \leq N \leq 50,000 2≤N≤50,000),牛棚方便…

洛谷P3128 [USACO15DEC] Max Flow P

洛谷题目传送门

题目描述

Farmer John 在他的谷仓中安装了 N − 1 N-1 N1 条管道,用于在 N N N 个牛棚之间运输牛奶( 2 ≤ N ≤ 50 , 000 2 \leq N \leq 50,000 2N50,000),牛棚方便地编号为 1 … N 1 \ldots N 1N。每条管道连接一对牛棚,所有牛棚通过这些管道相互连接。

FJ 正在 K K K 对牛棚之间泵送牛奶( 1 ≤ K ≤ 100 , 000 1 \leq K \leq 100,000 1K100,000)。对于第 i i i 对牛棚,你被告知两个牛棚 s i s_i si t i t_i ti,这是牛奶以单位速率泵送的路径的端点。FJ 担心某些牛棚可能会因为过多的牛奶通过它们而不堪重负,因为一个牛棚可能会作为许多泵送路径的中转站。请帮助他确定通过任何一个牛棚的最大牛奶量。如果牛奶沿着从 s i s_i si t i t_i ti 的路径泵送,那么它将被计入端点牛棚 s i s_i si t i t_i ti,以及它们之间路径上的所有牛棚。

输入格式

输入的第一行包含 N N N K K K

接下来的 N − 1 N-1 N1 行每行包含两个整数 x x x y y y x ≠ y x \ne y x=y),描述连接牛棚 x x x y y y 的管道。

接下来的 K K K 行每行包含两个整数 s s s t t t,描述牛奶泵送路径的端点牛棚。

输出格式

输出一个整数,表示通过谷仓中任何一个牛棚的最大牛奶量。

输入输出样例 #1

输入 #1

5 10
3 4
1 5
4 2
5 4
5 4
5 4
3 5
4 3
4 3
1 3
3 5
5 4
1 5
3 4

输出 #1

9

说明/提示

2 ≤ N ≤ 5 × 1 0 4 , 1 ≤ K ≤ 1 0 5 2 \le N \le 5 \times 10^4,1 \le K \le 10^5 2N5×104,1K105

题目分析

我们把题目简化一下:

给定一颗无向图 E E E,输入 K K K个数 x , y x,y x,y,对于每个 x , y x,y x,y,将路径 [ x , y ] [x,y] [x,y]上的所有点权加 1,试求出

点权最大的点 u u u

由此,我们便很容易看出这是一道树链剖分的题,而且是重链剖分

由此,我们便有两个思路:

F i r s t : First: First:

我们将原来的树链剖分的线段树转换为一个差分,最后只需求出前缀和即可。

该思路的比较简单,我就不写了

S e c o n d : Second: Second:

由于要将一条链上的所有点权都加 1 ,那我们很自然就想到了线段树的区间修改,由于要用到懒标

记,我们的代码会很长很长,正好可以复习一下线段树区间修改

Code:

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int h[N],to[N],ne[N],tot,a[N];
void add(int u,int v){tot++;to[tot]=v;ne[tot]=h[u];h[u]=tot;
}
int n,m;
struct tre{int data,l,r,lzy;//data为区间[l,r]的区间和,lzy为懒标记
};
class Segment_tree{//线段树模板(懒标记+区间修改+区间查询)
private:int w[N*4];//建树时叶子节点点权tre tree[N*4];void pushup(int u){tree[u].data=tree[u*2].data+tree[u*2+1].data;}//由下而上更新datavoid add(int u,int v){tree[u].data+=(tree[u].r-tree[u].l+1)*v;tree[u].lzy+=v;}//将 u 点对应区间中的每一个点都加上 vvoid pushdown(int u){//懒标记下传到左右子树if(!tree[u].lzy)return;add(u*2,tree[u].lzy);add(u*2+1,tree[u].lzy);//左右子树分别加上 tree[u].lzytree[u].lzy=0;//易错点:懒标记下传后一定要清零}void _build(int u,int l,int r){//建树tree[u]={0,l,r,0};if(l==r){tree[u].data=w[l];return;}//注意:一定是区间对应实际值,而非节点编号int mid=(l+r)/2;_build(u*2,l,mid);_build(u*2+1,mid+1,r);//分别建立左右子树pushup(u);//向上整合区间和}void modify(int u,int x,int y,int v){//将区间[x,y]的每一个值都加上 vint l=tree[u].l,r=tree[u].r;if(l>y||r<x)return;//如果当前节点对应区间与目标区间无交集,退出if(x<=l&&r<=y){add(u,v);return;}//如果当前区间为目标区间的子集,直接加pushdown(u);//注意:无论何时要访问子节点就要下传懒标记modify(u*2,x,y,v);modify(u*2+1,x,y,v);//细分区间修改pushup(u);//向上更新修改后的值}int getsum(int u,int x,int y){int l=tree[u].l,r=tree[u].r;if(l>y||r<x)return 0;//无交集,直接退(返回一个不影响答案的值)if(x<=l&&r<=y){return tree[u].data;}//为自己,返回(全部)值pushdown(u);//访问子(节点),传(懒)标记return getsum(u*2,x,y)+getsum(u*2+1,x,y);//合答案}
public://对外封装void build(int l,int r,int a[]){//以a[]为叶子节点的值建树memcpy(w,a,sizeof(w));_build(1,l,r);}void update(int l,int r,int v){modify(1,l,r,v);}//将区间[l,r]的值加上vint sum(int l,int r){return getsum(1,l,r);}//求区间[l,r]的和
};
class Heavy_chain_decomposition{//重链剖分
private:int id[N],reid[N*4],siz[N],fa[N],dep[N],son[N],top[N],tim,w[N];
//重链剖分数组:
//id[u]:u节点在线段树中的编号
//reid[u]:线段树中u点对应的节点
//siz[u]:u节点及其子树大小
//fa[u]:u节点的父节点
//dep[u]:u节点的深度(dep越大,深度越大,id越大,节点越靠下)
//son[u]:u节点的重儿子(siz最大的儿子)
//top[u]:u节点所在链的链头(dep最小的节点)
//tim:访问时间,用来标号
//w:建树数组Segment_tree tr;//剖分出的链对应线段树void dfs1(int u,int fath,int dp){//第一次深搜求出dep,siz,fa,son
//u为当前节点,fath为父节点,dp为深度dep[u]=dp;siz[u]=1;fa[u]=fath;//更新dep,siz,fa(siz初始值为1:包括u节点)for(int i=h[u];i;i=ne[i]){//向下找子节点int v=to[i];if(v==fath)continue;//不能跑回去dfs1(v,u,dp+1);//先向下搜,在整合sizsiz[u]+=siz[v];//整合siz[u]if(siz[v]>siz[son[u]])son[u]=v;//求出重儿子}}void dfs2(int u,int fath,int ori){//第二次深搜求出id,reid,top
//u为当前节点,fath为父节点,ori为当前节点所在链的链头
//Q:为什么要第二次深搜才能求出id?
//A:因为我们第一次深搜是乱访问的,没有遵循先重(儿子)后轻(儿子)的顺序id[u]=++tim;reid[id[u]]=u;top[u]=ori;//更新id,reid,top值if(son[u]){dfs2(son[u],u,ori);}//有重儿子就先访问,生成重链
//重链上的点都是重儿子,这样经过的点会更多(注意不是链上点更多)for(int i=h[u];i;i=ne[i]){int v=to[i];if(v==fath||v==son[u])continue;dfs2(v,u,v);//生成轻链}}void build_tree(int u){//建树:建立线段树dfs1(u,0,0);dfs2(u,0,u);tr.build(1,n,w);}
public://对外封装void change(int a[]){//将a数组中每个点对应的值转化到线段树叶子节点对应的值上for(int i=1;i<=n;i++)w[id[i]]=a[i];}void build(int u,int a[]){//以u点的点权为a[u]建树change(a);build_tree(u);}void update(int x,int y,int v){//将路径[x,y]上的每一个点的点权都加上vwhile(top[x]!=top[y]){//一直向上跳,直到跳到同一条链上if(dep[top[x]]<dep[top[y]])swap(x,y);//链头深(dep大)的先跳tr.update(id[top[x]],id[x],v);//跳的时候将经过的点权都加vx=fa[top[x]];//跳到链头的父节点(更高一条链)}if(dep[x]>dep[y])swap(x,y);//已经到同一条链上了,让x的id小(dep小),方便修改tr.update(id[x],id[y],v);//修改}int sum(int x,int y){int res=0;while(top[x]!=top[y]){//跳(到链头)同高if(dep[top[x]]<dep[top[y]])swap(x,y);//(深度)深先跳res+=tr.sum(id[top[x]],id[x]);//累加(点权)和x=fa[top[x]];//(向)上跳(到更高的)链}if(dep[x]>dep[y])swap(x,y);//(深度)小在前res+=tr.sum(id[x],id[y]);return res;}
}tr;
int main(){cin>>n>>m;for(int i=1;i<=n-1;i++){int x,y;cin>>x>>y;add(x,y);add(y,x);}tr.build(1,a);//一开始为空树for(int i=1;i<=m;i++){int x,y;cin>>x>>y;tr.update(x,y,1);}int ans=0;for(int i=1;i<=n;i++)ans=max(ans,tr.sum(i,i));cout<<ans<<'\n';return 0;
}

总结

树链剖分和线段树告诉了我们一个道理:不要有畏难情绪,理解了再难的代码也能打出来

http://www.dtcms.com/wzjs/297586.html

相关文章:

  • 嵌入式培训班多少钱seo专业培训中心
  • 扁平化风格网站模板关键词优化软件排行
  • 保险网站源码数据分析培训
  • 哈尔滨网络科技公司网站网站运营怎么做
  • 网站打开显示站点目录为什么不能去外包公司
  • 怎么看网站的服务器打开网址资料网站
  • 泉州网站制作专业策划方案
  • 上海稼禾建设装饰集团网站最新国际新闻 大事件
  • php制作投票网站兰州seo优化公司
  • 建网站去哪里备案谷歌推广教程
  • 平湖网站制作全渠道营销管理平台
  • 手机网站域名m打头营销比较成功的品牌
  • 南昌科技网站建设男生技能培训班有哪些
  • 如何引用网站上的资料做文献世界互联网峰会
  • 自己可以建立网站吗广州seo排名优化服务
  • 互联网网站开发服务合同百度纯净版首页入口
  • 企业网站系统设计搜索引擎推广简称
  • 备案域名做的网站别人用来诈骗百度免费推广网站
  • 悦阁网站建设购买网站域名
  • 从零学习做网站百度竞价推广点击软件奔奔
  • 互联网app网站建设方案模板下载百度在线识图查图片
  • 做网站一个月能赚多少钱惠州企业网站建设
  • 如果做公司网站佛山百度推广公司
  • 网站建设技术外文文献免费发广告的软件
  • 杭州网站建设制作公司厦门seo屈兴东
  • 深圳网站设计收费网站推广公司哪家好
  • 那个网站学做披萨比较好网站查询器
  • 舆情分析是什么郑州seo培训
  • 内蒙古住房建设部官方网站google秒收录方法
  • 哪个网站可以自己做名片安康seo