[USACO15DEC]最大流Max Flow(树链剖分,线段树)

FJ给他的牛棚的N(2≤N≤50,000)个隔间之间安装了N-1根管道,隔间编号从1到N。所有隔间都被管道连通了。

FJ有K(1≤K≤100,000)条运输牛奶的路线,第i条路线从隔间si运输到隔间ti。一条运输路线会给它的两个端点处的隔间以及中间途径的所有隔间带来一个单位的运输压力,你需要计算压力最大的隔间的压力是多少。

思路:

比较基础的树剖题

对于每条线路

我们维护一个区间最大值的线段树

通过树剖实现每个加1的操作

最后读取总最大值就好

代码:

// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#define rii register int i
#define rij register int j
using namespace std;
int fa[50005],top[50005],size[50005],nid[50005];
int head[50005],n,k,bnt,cnt,sd[50005],wes[50005];
struct ljb{
    int to,nxt;
}y[100005];
struct tree{
    int maxn,lazy;
}x[800005];
inline int rd(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {f=ch==‘-‘?0:1;ch=getchar();}
    while(isdigit(ch))  {x=(x<<1)+(x<<3)+ch-‘0‘;ch=getchar();}
    return f?x:-x;
}
inline void add(int from,int to)
{
    bnt++;
    y[bnt].to=to;
    y[bnt].nxt=head[from];
    head[from]=bnt;
}
inline void pushdown(int bh)
{
    x[bh*2].lazy+=x[bh].lazy;
    x[bh*2].maxn+=x[bh].lazy;
    x[bh*2+1].lazy+=x[bh].lazy;
    x[bh*2+1].maxn+=x[bh].lazy;
    x[bh].lazy=0;
}
void addjl(int l,int r,int nl,int nr,int bh)
{
    if(l<nl)
    {
        l=nl;
    }
    if(r>nr)
    {
        r=nr;
    }
    if(l==nl&&r==nr)
    {
        x[bh].lazy++;
        x[bh].maxn++;
        return;
    }
    if(x[bh].lazy!=0)
    {
        pushdown(bh);
    }
    int mid=(nl+nr)/2;
    if(l<=mid)
    {
        addjl(l,r,nl,mid,bh*2);
    }
    if(r>mid)
    {
        addjl(l,r,mid+1,nr,bh*2+1);
    }
    x[bh].maxn=max(x[bh*2].maxn,x[bh*2+1].maxn);
}
void dfs1(int wz,int nfa,int nsd)
{
    fa[wz]=nfa;
    sd[wz]=nsd;
    size[wz]=1;
    int maxn=0;
    for(rii=head[wz];i!=0;i=y[i].nxt)
    {
        int to=y[i].to;
        if(to!=nfa)
        {
            dfs1(to,wz,nsd+1);
            size[wz]+=size[to];
            if(size[to]>maxn)
            {
                wes[wz]=to;
                maxn=size[to];
            }
        }
    }
}
void dfs2(int wz,int ntop)
{
    cnt++;
    nid[wz]=cnt;
    top[wz]=ntop;
    if(wes[wz]==0)
    {
        return;
    }
    dfs2(wes[wz],ntop);
    for(rii=head[wz];i!=0;i=y[i].nxt)
    {
        int to=y[i].to;
        if(wes[wz]!=to&&fa[wz]!=to)
        {
            dfs2(to,to);
        }
    }
}
void addlj(int from,int to)
{
    while(top[from]!=top[to])
    {
        if(sd[top[from]]<sd[top[to]])
        {
            swap(from,to);
        }
        addjl(nid[top[from]],nid[from],1,n,1);
        from=fa[top[from]];
    }
    if(sd[from]>sd[to])
    {
        swap(from,to);
    }
    addjl(nid[from],nid[to],1,n,1);
    from=fa[top[from]];
}
int main()
{
//    freopen("1.in","r",stdin);
//    freopen("1.out","w",stdout);
    n=rd(),k=rd();
    for(rii=1;i<n;i++)
    {
        int from,to;
        from=rd(),to=rd();
        add(from,to);
        add(to,from);
    }
    dfs1(1,0,0);
    dfs2(1,1);
    for(rii=1;i<=k;i++)
    {
        int from,to;
        from=rd(),to=rd();
        addlj(from,to);
    }
    cout<<x[1].maxn;
}

原文地址:https://www.cnblogs.com/ztz11/p/9926215.html

时间: 2024-07-31 01:04:04

[USACO15DEC]最大流Max Flow(树链剖分,线段树)的相关文章

Aizu 2450 Do use segment tree 树链剖分+线段树

Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show.php?pid=39566 Description Given a tree with n (1 ≤ n ≤ 200,000) nodes and a list of q (1 ≤ q ≤ 100,000) queries, process the queries in order and out

HDU-3966 Aragorn&#39;s Story(树链剖分+线段树)

Aragorn's Story Time Limit: 10000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 12479    Accepted Submission(s): 3331 Problem Description Our protagonist is the handsome human prince Aragorn comes from The Lor

SPOJ - QTREE 375 Query on a tree 树链剖分+线段树

操作1:修改第k条边权. 操作2:询问两点间最大边权. 树链剖分,然后线段树维护最大值 #include<cstdio> #include<cstring> #include<cmath> #include<iostream> #include<algorithm> #include<set> #include<map> #include<queue> #include<vector> #inclu

【CF725G】Messages on a Tree 树链剖分+线段树

[CF725G]Messages on a Tree 题意:给你一棵n+1个节点的树,0号节点是树根,在编号为1到n的节点上各有一只跳蚤,0号节点是跳蚤国王.现在一些跳蚤要给跳蚤国王发信息.具体的信息传输过程如下: 1.信息的发起者把信息上传给他父亲节点处的跳蚤,然后自身进入等待状态.3.跳蚤国王在收到信息时会将信息立刻下传到发来信息的那个儿子,跳蚤国王可以在同一时刻下传多份信息.4.上传:a把信息传给b.如果b正处于等待状态,则b会立刻将a发来的信息下传回去.如果同时有好多个信息传给b,则b会

bzoj 2157: 旅游【树链剖分+线段树】

裸的树链剖分+线段树 但是要注意一个地方--我WA了好几次才发现取完相反数之后max值和min值是要交换的-- #include<iostream> #include<cstdio> using namespace std; const int N=200005; int n,m,h[N],cnt,de[N],va[N],fa[N],si[N],hs[N],fr[N],id[N],tot,rl[N]; char c[10]; struct qwe { int ne,no,to,va

Hdu 3966 Aragorn&#39;s Story (树链剖分 + 线段树区间更新)

题目链接: Hdu 3966 Aragorn's Story 题目描述: 给出一个树,每个节点都有一个权值,有三种操作: 1:( I, i, j, x ) 从i到j的路径上经过的节点全部都加上x: 2:( D, i, j, x ) 从i到j的路径上经过的节点全部都减去x: 3:(Q, x) 查询节点x的权值为多少? 解题思路: 可以用树链剖分对节点进行hash,然后用线段树维护(修改,查询),数据范围比较大,要对线段树进行区间更新 1 #include <cstdio> 2 #include

【bzoj3589】动态树 树链剖分+线段树

题目描述 别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件 事件0:这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子. 事件1:小明希望你求出几条树枝上的果子数. 一条树枝其实就是一个从某个节点到根的路径的一段. 每次小明会选定一些树枝, 让你求出在这些树枝上的节点的果子数的和. 注意, 树枝之间可能会重合, 这时重合的部分的节点的果子只要算一次. 输入 第一行一个整数n(1<=n<=200,000), 即节点数. 接下来n-1行, 每行两个数字u,

BZOJ2243 (树链剖分+线段树)

Problem 染色(BZOJ2243) 题目大意 给定一颗树,每个节点上有一种颜色. 要求支持两种操作: 操作1:将a->b上所有点染成一种颜色. 操作2:询问a->b上的颜色段数量. 解题分析 树链剖分+线段树. 开一个记录类型,记录某一段区间的信息.l 表示区间最左侧的颜色 , r 表示区间最右侧的颜色 , sum 表示区间中颜色段数量. 合并时判断一下左区间的右端点和有区间的左端点的颜色是否一样. 树上合并时需要用两个变量ans1,ans2来存储.ans1表示x往上走时形成的链的信息,

bzoj4304 (树链剖分+线段树)

Problem T2 (bzoj4304 HAOI2015) 题目大意 给定一颗树,1为根节点,要求支持三种操作. 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a . 操作 3 :询问某个节点 x 到根的路径中所有点的点权和. 解题分析 练手题.树链剖分+线段树. 参考程序 1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 #incl

【BZOJ】1146: [CTSC2008]网络管理Network(树链剖分+线段树套平衡树+二分 / dfs序+树状数组+主席树)

第一种做法(时间太感人): 这题我真的逗了,调了一下午,疯狂造数据,始终找不到错. 后来发现自己sb了,更新那里没有打id,直接套上u了.我.... 调了一下午啊!一下午的时光啊!本来说好中午A掉去学习第二种做法,噗 好吧,现在第一种做法是hld+seg+bst+二分,常数巨大,log^4级别,目前只会这种. 树剖后仍然用线段树维护dfs序区间,然后在每个区间建一颗平衡树,我用treap,(这题找最大啊,,,囧,并且要注意,这里的rank是比他大的数量,so,我们在二分时判断要判断一个范围,即要