首页 > 其他分享 >P6666 [清华集训2016] 数据交互 题解

P6666 [清华集训2016] 数据交互 题解

时间:2023-02-24 16:46:37浏览次数:29  
标签:int 题解 LCA tp dfn maxl lca 2016 P6666

##

P6666 [清华集训2016] 数据交互 题解

###

简要题意:

n个点的树,m次操作,分别为添加一条路径$(u_i,v_i,w_i)$,和撤消一条路径,每一次操作后求出一条路径使得与这条路径有交的路径的权值和最大
。 ###
题解:

先考虑如何表示所有与一条路径(记为$(u,v)$)有交的路径(记为$(x,y)$)

1.$\mathrm{LCA}(x,y)\in(u,v)$且$\mathrm{LCA}(x,y)\ne \mathrm{LCA}(u,v)$

2.$\mathrm{LCA}(u,v)\in(x,y)$

于是我们可以记$w_i$表示所有$\mathrm{LCA}(u,v)=i$的权值和,$g_i$表示所有 $i\in(u,v)$的路径的权值和。然后我们可以把一条路径有交的权值和写成非常漂亮的形式:路径上除了 $\rm LCA$的$w_i$和$g_{\mathrm{LCA}}$。

这样每次修改时就只用改$w_{\mathrm{LCA}}$和其他点的$g_i$的值。

首先我们给每个点 v 开一个可删除堆表示v的虚子树中到 v 的最长链,再开一个全局的可删除堆记录每条重链贡献的答案。

我们发现,一条路径可以看成是重链上的$u,v$两点(其中$u$是$\mathrm{LCA}$),以及这两点分别向虚子树伸出去的一条最长链(可以为空)。它的权值为这条链的$w_i$之和再加上$g_u$,当$u$等于$v$的时候,我们需要找最长链和次长链。

然后我们发现这就是一个最大子段和的问题。对于线段树上的每一个节点,我们维护:

$maxl$:从前节点包含的区间最左边(深度最小)的结点开始的最长链。

$maxr$: 从前节点包含的区间最右边(深度最小)的结点开始的最长链。

$maxn$: 当前区间的答案

$sum$: 当前区间的$w_i$之和


一条重链的链顶的最长链就是这条重链对应的$maxl$。

在修改的时候,我们先删除$lca$以上$log$条重链对答案的贡献,然后修改链上点的$g$和$lca$的$w$,再更新答案。

代码:(略微有点长)
``

#include<bits/stdc++.h>
#define ll long long
#define mid ((l+r)>>1)
#define ls (rt<<1)
#define rs (rt<<1|1)
using namespace std;
inline int read(){
    int s=0;
    char ch=getchar();
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch>='0'&&ch<='9')s=(s<<3)+(s<<1)+(ch^48),ch=getchar();
    return s;
}
inline void write(ll x){
    if(x>=10)write(x/10);
    putchar(x%10+48);
}
const int N=100501;
int n,m;
vector<int>e[N];
int fa[N],dep[N],tp[N],tot,dfn[N],siz[N],son[N],bot[N],id[N];
struct HEAP{
    priority_queue<ll>del,q;
    inline void POP(){
        while(del.size()&&del.top()==q.top()){
            del.pop(),q.pop();
        }
    }
    inline void PUSH(ll x){
        POP();
        q.push(x);
    }
    inline void DEL(ll x){
        del.push(x);
    }
    inline ll fi(){
        POP();
        return q.top();
    }
    inline ll se(){
        ll x=fi();
        DEL(x);
        ll y=fi();
        PUSH(x);
        return y;
    }
}ANS,q[N];
struct node{
    int l,r;
    ll maxl,maxr,maxn,sum,lz;
    node(){l=r=maxl=maxr=maxn=sum=lz=0;}
};
node operator +(const node &a,const node &b){
    node c;
    c.l=a.l,c.r=b.r;
    c.maxn=max(max(a.maxn,b.maxn),a.maxr+b.maxl);
    c.maxl=max(a.maxl,a.sum+b.maxl);
    c.maxr=max(b.maxr,b.sum+a.maxr);
    c.sum=a.sum+b.sum;
    return c;
}
struct SEG{
    node t[N<<2];
    inline void upd(int rt,int p){
        int x=id[p];
        ll fi=q[x].fi(),se=q[x].se();
        t[rt].maxl=fi+t[rt].sum;
        t[rt].maxr=fi+t[rt].sum+t[rt].lz;
        t[rt].maxn=fi+se+t[rt].sum+t[rt].lz;
    }
    inline void build(int rt,int l,int r){
        if(l==r){
            upd(rt,l);
            return;
        }
        build(ls,l,mid),build(rs,mid+1,r);
        t[rt]=t[ls]+t[rs];
    }
    inline void psh(int rt,int x){
        t[rt].maxn+=x,t[rt].maxr+=x,t[rt].lz+=x;
    }
    inline void pshlz(int rt){
        if(t[rt].lz){
            psh(ls,t[rt].lz),psh(rs,t[rt].lz);
            t[rt].lz=0;
        }
    }
    inline void modify(int rt,int l,int r,int L,int R,ll x){
        if(L<=l&&r<=R){
            psh(rt,x);
            return;
        }
        pshlz(rt);
        if(L<=mid)modify(ls,l,mid,L,R,x);
        if(mid<R)modify(rs,mid+1,r,L,R,x);
        t[rt]=t[ls]+t[rs];
    }
    inline void modify(int rt,int l,int r,int x,ll p){
        t[rt].sum+=p;
        if(l==r){
            t[rt].maxr+=p,t[rt].maxn+=p,t[rt].maxl+=p;
            return;
        }
        pshlz(rt);
        if(x<=mid)modify(ls,l,mid,x,p);
        else modify(rs,mid+1,r,x,p);
        t[rt]=t[ls]+t[rs];
    }
    inline void change(int rt,int l,int r,int x){
        if(l==r){
            upd(rt,x);
            return;
        }
        pshlz(rt);
        if(x<=mid)change(ls,l,mid,x);
        else change(rs,mid+1,r,x);
        t[rt]=t[ls]+t[rs];
    }
    inline node query(int rt,int l,int r,int L,int R){
        if(L<=l&&r<=R)return t[rt];
        pshlz(rt);
        if(L>mid)return query(rs,mid+1,r,L,R);
        else if(R<=mid)return query(ls,l,mid,L,R);
        else return query(ls,l,mid,L,mid)+query(rs,mid+1,r,mid+1,R);
    }
}T;
struct queryoption{
    int x,y,w;
}op[N];
inline void dfs(int x){
    siz[x]=1;
    for(auto y:e[x]){
        if(y!=fa[x]){
            fa[y]=x;
            dep[y]=dep[x]+1;
            dfs(y);
            siz[x]+=siz[y];
            if(siz[y]>siz[son[x]])son[x]=y;
        }
    }
}
inline void dfs1(int x,int topp){
    dfn[x]=++tot;
    id[tot]=x;
    tp[x]=topp;
    bot[x]=x;
    if(son[x])dfs1(son[x],topp),bot[x]=bot[son[x]];
    for(auto y:e[x]){
        if(y!=fa[x]&&y!=son[x])dfs1(y,y);
    }
}   
inline int get_lca(int u,int v){
    while(tp[u]!=tp[v]){
        if(dep[tp[u]]<dep[tp[v]])swap(u,v);
        u=fa[tp[u]];
    }
    return dep[u]<dep[v]?u:v;
}
inline void add(int u,int v){
    node c;
    while(tp[u]!=tp[v]){
        if(dep[tp[u]]<dep[tp[v]])swap(u,v);
        c=T.query(1,1,n,dfn[tp[u]],dfn[bot[u]]);
        ANS.PUSH(c.maxn);
        u=fa[tp[u]];
    }
    c=T.query(1,1,n,dfn[tp[u]],dfn[bot[u]]);
    ANS.PUSH(c.maxn);
}
inline void del(int u,int v){
    node c;
    while(tp[u]!=tp[v]){
        if(dep[tp[u]]<dep[tp[v]])swap(u,v);
        c=T.query(1,1,n,dfn[tp[u]],dfn[bot[u]]);
        ANS.DEL(c.maxn);
        u=fa[tp[u]];
    }
    c=T.query(1,1,n,dfn[tp[u]],dfn[bot[u]]);
    ANS.DEL(c.maxn);
}
inline void modify(int u,int v,int w){
    while(tp[u]!=tp[v]){
        if(dep[tp[u]]<dep[tp[v]])swap(u,v);
        T.modify(1,1,n,dfn[tp[u]],dfn[u],w);
        u=fa[tp[u]];
    }
    if(dep[u]>dep[v])swap(u,v);
    T.modify(1,1,n,dfn[u],dfn[v],w);
}
inline void solve(int u,int v,int w){
    int lca=get_lca(u,v);
    node c;
    for(int i=tp[lca];i;i=tp[fa[i]]){
        c=T.query(1,1,n,dfn[i],dfn[bot[i]]);
        if(fa[i])q[fa[i]].DEL(c.maxl);
        if(i!=tp[lca]){
            ANS.DEL(c.maxn);
        }
    }
    del(u,v);
    T.modify(1,1,n,dfn[lca],w);
    modify(u,v,w);
    modify(lca,lca,-w);
    add(u,v);
    for(int i=tp[lca];i;i=tp[fa[i]]){
        c=T.query(1,1,n,dfn[i],dfn[bot[i]]);
        if(fa[i])q[fa[i]].PUSH(c.maxl),T.change(1,1,n,dfn[fa[i]]);
        if(i!=tp[lca]){
            ANS.PUSH(c.maxn);
        }
    }
}
int main(){
    n=read(),m=read();
    for(int i=1;i<n;i++){
        int x=read(),y=read();
        e[x].push_back(y),e[y].push_back(x);
    }  
    for(int i=1;i<=n;i++)q[i].PUSH(0),q[i].PUSH(0);
    dfs(1);
    dfs1(1,1);    
    for(int i=1;i<=n;i++)if(i==tp[i])ANS.PUSH(0);
    char ch;
    T.build(1,1,n);
    for(int i=1;i<=m;i++){
        while(ch=getchar(),ch!='-'&&ch!='+');
        if(ch=='+'){
            op[i].x=read(),op[i].y=read(),op[i].w=read();
            solve(op[i].x,op[i].y,op[i].w);
        }
        else{
            int x=read();
            solve(op[x].x,op[x].y,-op[x].w);
        }
        write(ANS.fi());
        puts("");
    }
    return 0;
}

 

标签:int,题解,LCA,tp,dfn,maxl,lca,2016,P6666
From: https://www.cnblogs.com/Xttttr/p/17152038.html

相关文章

  • P8422 题解
    前言题目传送门!更好的阅读体验?第三道大模拟,写篇题解庆祝一下。文中粗体字是我踩坑的地方,欢迎统计我被坑了多少次。思路终局奖分很简单,放在主函数里,所以我们看每次的......
  • 树剖练习题题解总和(动态更新)
    这篇博客的练习题题解1、P3384【模板】轻重链剖分/树链剖分模板题,详见此#include<iostream>#include<cstdio>#include<vector>usingnamespacestd;intn,m,r,p,t[......
  • P3571 [POI2014]SUP-Supercomputer 题解
    首先有一个结论,树中存在一个深度\(dep\),使得深度小于等于\(dep\)的点只需\(dep\)次覆盖完,而大于\(dep\)的除最后一次外其他每次都可以填充\(k\)次。证明:在\(dep......
  • P4768 [NOI2018] 归程 题解
    这是一个悲伤的题目,自这道题后,\(\text{Noi}\)再无\(\text{SPFA}\)。首先讲一下重构树是啥。重构树是基于\(\text{kurskal生成树}\)算法的一棵树,对于每一次合并一条......
  • P3247 [HNOI2016]最小公倍数 题解
    题意简述:给定一个无向图,边权带两个值\((a,b)\),给定\(q\)次询问,每次询问给定两个点,求两个点直接是否有\(\max(a)=x\)且\(\max(b)=y\)的简单或非简单路径。解:如果......
  • P2489 [SDOI2011]迷宫探险 题解
    题意简述:一个\(n\timesm\)的带墙体单入口多出口迷宫中有\(k\)个陷阱,陷阱分为有害或无害,有害会使人掉血,给出所有垃圾的有害与无害的所有排列组成的概率,给定人的血量,求......
  • P4416 [COCI2017-2018#1] Plahte 题解
    题意简述:给定\(n\)个互不相交,可以重叠的矩阵,对某些点染色,这个点上的所有矩阵会被染上这个颜色,求最后每个矩阵会有多少种颜色。解:我们可以先把矩阵拆成上下两条水平线......
  • CF1034A Enlarge GCD 题解
    题意简述:删去最少的数使所有的数的\(\text{gcd}\)增加。解:先对每个数除以所有数的\(\text{gcd}\),然后剩下的需要找到所有数的质因子,找到一个最多的序列中数拥有的质......
  • CF436E Cardboard Box 题解
    一道经典的反悔贪心题。考虑每次选择使总星数加一,那么总共有四种情况。一、对于一关没有星,选一颗星,代价为\(a_i\)。二、对于一关有一颗星,再选一颗星,代价为\(b_i-a_i\)......
  • CF204E Little Elephant and Strings 题解
    由于是多个串,还与每个子串的信息有关,很容易想到用SA或广义SAM。这里选择用SA。首先先把字符串转化为数组,连接起来,中间用一些不会出现的数。处理出后缀数组与\(height......