[SDOI2016]游戏 树剖+李超树

链接

https://www.luogu.org/problemnew/show/P4069

思路

树剖+超哥线段树
我已经自毙了,自闭了!!!!

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
using namespace std;
const ll N=400007LL;
const ll inf=123456789123456789LL;
ll read() {
    ll x=0,f=1;char s=getchar();
    for(;s>'9'||s<'0';s=getchar()) if(s=='-') f=-1;
    for(;s>='0'&&s<='9';s=getchar()) x=x*10+s-'0';
    return x*f;
}
struct node {
    ll v,nxt,q;
}e[N<<1];
ll n,m,head[N<<1],tot;
ll top[N],idx[N],fun[N],siz[N],f[N],son[N],dep[N],dis[N],js;
void add(ll u,ll v,ll q) {
    e[++tot].v=v,e[tot].q=q,e[tot].nxt=head[u],head[u]=tot;
}
namespace seg_tree {
    #define ls rt<<1
    #define rs rt<<1|1
    struct node {
        ll l,r;
        ll a,b,mi,t;
    }e[N<<2];
    bool tag[N<<2];
    ll calc(ll a,ll b,ll id) {return a*dis[fun[id]]+b;}
    void build(ll l,ll r,ll rt) {
        e[rt].l=l,e[rt].r=r;
        e[rt].b=e[rt].mi=inf;
        if(l==r) return;
        ll mid=(l+r)>>1;
        build(l,mid,ls);
        build(mid+1,r,rs);
    }
    bool cmp(ll a,ll b,ll c,ll d,ll id) {return calc(a,b,id)>calc(c,d,id);}
    void modify(ll l,ll r,ll a,ll b,ll L,ll R,ll rt) {
        if(L<=e[rt].l&&e[rt].r<=R) {//写法注意
//            if(cmp(a,b,e[rt].a,e[rt].b,e[rt].l)&&cmp(a,b,e[rt].a,e[rt].b,e[rt].r)) return;
//            if(cmp(e[rt].a,e[rt].b,a,b,e[rt].l)&&cmp(e[rt].a,e[rt].b,a,b,e[rt].r)) {
//              tag[rt]=1;
//                e[rt].a=a,e[rt].b=b;
//              e[rt].mi=min(e[rt].mi,(calc(a,b,e[rt].l),calc(a,b,e[rt].r)));
//                return;
//            }
//            if(e[rt].l==e[rt].r) return;
            bool cmp1 = (calc(e[rt].a,e[rt].b,l) <= calc(a,b,l));
            bool cmp2 = (calc(e[rt].a,e[rt].b,r) <= calc(a,b,r));
            if (cmp1 && cmp2) return;
            if ((!cmp1) && (!cmp2)) {
                tag[rt]=1;
                e[rt].mi = min(e[rt].mi, min(calc(a,b,l), calc(a,b,r)));
                e[rt].a=a,e[rt].b=b;
//              cout<<l<<" "<<r<<" "<<e[rt].mi<<"<<<<<<<<\n";
                return;
            }
            ll mid=(e[rt].l+e[rt].r)>>1;
            bool cmp3 = (calc(e[rt].a,e[rt].b,mid) <= calc(a,b,mid));
            if (!cmp3) {
                swap(e[rt].a,a);swap(e[rt].b,b);swap(cmp1, cmp2);
            }
            if (cmp2) {
                modify(l,mid,a,b,L,R,ls);
            } else {
                modify(mid+1,r,a,b,L,R,rs);
            }
            e[rt].mi= min(min(e[ls].mi, e[rs].mi), min(calc(e[rt].a,e[rt].b,l), calc(e[rt].a,e[rt].b,r)));
            return;
        }
        ll mid=(e[rt].l+e[rt].r)>>1;
        if(L<=mid) modify(l,mid,a,b,L,R,ls);
        if(R>mid) modify(mid+1,r,a,b,L,R,rs);
        e[rt].mi= min(min(e[ls].mi, e[rs].mi), min(calc(e[rt].a,e[rt].b,l), calc(e[rt].a,e[rt].b,r)));
//        pushup(rt);
    }
    ll query(ll l,ll r,ll L,ll R,ll rt) {
        if(L<=e[rt].l&&e[rt].r<=R) {
//          cout<<e[rt].l<<" "<<e[rt].r<<"!!\n";
//          cout<<e[rt].mi<<"!!\n";
            return e[rt].mi;
        }
        ll mid=(e[rt].l+e[rt].r)>>1;
//        int ans = min(ans, min(cal(lp, bst[pos]), cal(rp, bst[pos])));
        ll ans= min(calc(e[rt].a,e[rt].b,max(L,l)),calc(e[rt].a,e[rt].b,min(r,R))) ;//注意
        if(L<=mid) ans=min(query(l, mid,L,R,ls),ans);
        if(R>mid) ans=min(query(mid+1,r,L,R,rs),ans);
        return ans;
    }
}
namespace tree {
    void dfs1(ll u,ll fa) {
        siz[u]=1;
        f[u]=fa;
        dep[u]=dep[fa]+1;
        for(ll i=head[u];i;i=e[i].nxt) {
            ll v=e[i].v;
            if(v==fa) continue;
            dis[v]=dis[u]+e[i].q;
            dfs1(v,u);
            siz[u]+=siz[v];
            if(siz[son[u]]<siz[v]) son[u]=v;
        }
    }
    void dfs2(ll u,ll topf) {
        top[u]=topf;
        idx[u]=++js;
        fun[js]=u;
        if(son[u]) dfs2(son[u],topf);
        for(ll i=head[u];i;i=e[i].nxt) {
            ll v=e[i].v;
            if(!idx[v]) dfs2(v,v);
        }
    }
    ll lca(ll s,ll t) {
        while(top[s]!=top[t]) {
            if(dep[top[s]]<dep[top[t]]) swap(s,t);
            s=f[top[s]];
        }
        return dep[s]<dep[t] ? s : t;
    }
    void CC(ll s,ll t,ll a,ll b) {
        while(top[s]!=top[t]) {
            if(dep[top[s]]<dep[top[t]]) swap(s,t);
            seg_tree:: modify(1,n,a,b,idx[top[s]],idx[s],1);
            s=f[top[s]];
        }
        if(dep[s]>dep[t]) swap(s,t);
        seg_tree::modify(1,n,a,b,idx[s],idx[t],1);
    }
    void QQ(ll s,ll t) {
        ll ans=inf;
        while(top[s]!=top[t]) {
            if(dep[top[s]]<dep[top[t]]) swap(s,t);
            ans=min(ans,seg_tree::query(1,n,idx[top[s]],idx[s],1));
//            cout<<idx[top[s]]<<" "<<idx[s]<<"\n";
            s=f[top[s]];
        }
        if(dep[s]>dep[t]) swap(s,t);
        ans=min(ans,seg_tree::query(1,n,idx[s],idx[t],1));
//        cout<<idx[s]<<" "<<idx[t]<<"\n";
        printf("%lld\n",ans);
    }
}
int main() {
//    freopen("game2.in","r",stdin);
    // freopen("a.out","w",stdout);
    n=read(),m=read();
    for(ll i=1;i<n;++i) {
        ll x=read(),y=read(),z=read();
        add(x,y,z),add(y,x,z);
    }
    tree::dfs1(1,0);
    tree::dfs2(1,1);
    seg_tree::build(1,n,1);
    for(ll i=1;i<=m;++i) {
        ll opt=read(),s=read(),t=read();
        if(opt==1) {
            ll a=read(),b=read();
            ll LCA=tree::lca(s,t);
            tree::CC(s,LCA,-a,a*dis[s]+b);
            tree::CC(t,LCA,a,a*dis[s]-2LL*a*dis[LCA]+b);
//             cout<<LCA<<"<\n";
//             cout<<-a<<" "<<a*dis[s]+b<<"<\n";
//             cout<<LCA<<" "<<t<<"\n";
//             cout<<a<<" "<<a*dis[s]-2LL*a*dis[LCA]+b<<"<\n";
        } else tree::QQ(s,t);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/dsrdsr/p/10358119.html

时间: 2024-10-27 06:03:41

[SDOI2016]游戏 树剖+李超树的相关文章

BZOJ4034 树上操作(树剖 线段树大模板)

BZOJ4034 long long 是大坑点 貌似long long 跟int 乘起来会搞事情?... A了这题线段树和树剖的基础OK 嘛 重点过掉的还是线段树区间更新的lazy tag吧 #include<cstdio> #include<cstring> #define N 100001 using namespace std; struct ed{ int nxt,to; }e[N*2]; int ne=0,head[N]; long long int w0[N]; str

poj3728The merchant树剖+线段树

如果直接在一条直线上,那么就建线段树 考虑每一个区间维护最小值和最大值和答案,就符合了合并的条件,一个log轻松做 那么在树上只要套一个树剖就搞定了,多一个log也不是问题 注意考虑在树上的话每一条链都有可能是正着被用和反着被用,所以存两个答案 所以维护信息只需要一个merge和一个reverse 代码如下: 1 #include <cstdio> 2 #include <iostream> 3 #define mid (l+r>>1) 4 using namespac

POJ3417Network(LCA+树上查分||树剖+线段树)

Yixght is a manager of the company called SzqNetwork(SN). Now she's very worried because she has just received a bad news which denotes that DxtNetwork(DN), the SN's business rival, intents to attack the network of SN. More unfortunately, the origina

[GX/GZOI2019]旧词(树上差分+树剖+线段树)

考虑k=1的做法:这是一道原题,我还写过题解,其实挺水的,但当时我菜还是看题解的:https://www.cnblogs.com/hfctf0210/p/10187947.html.其实就是树上差分后值为1. 考虑k>1的做法:其实可以再次树上差分,给每个点i赋值v[i]=dep[i]k-dep[i-1]k,然后还是和原来一样开一棵线段树,记录一个val[rt]表示当前节点内区间v值的和,以及sum[rt]表示区间值.修改时打标记,只需要将sum[rt]+=v*val[rt],lazy[rt]+

[SCOI2015]情报传递[树剖+主席树]

[SCOI2015]情报传递 题意大概就是 使得在 \(i\) 时刻加入一个情报员帮您传情报 然后询问 \(x,y,c\) 指 \(x\)到\(y\)多少个人有风险-(大于c)的都有风险-每天风险值+1 看起来-不太可做- 每次要整棵树+1复杂度也需要\(log^2\)的树套树吧 但是显然不用啊 查询的时候减掉就可以了- 所以直接树剖上面无脑主席树就可以了啊- #include <bits/stdc++.h> // #define int long long #define rep(a , b

bzoj 5210: 最大连通子块和【动态dp+树剖+线段树+堆】

参考:https://www.cnblogs.com/CQzhangyu/p/8632904.html 要开longlong的 首先看dp,设f[u]为必选u点的子树内最大联通块,p[u]为不一定选u的子树内最大联通块,转移很显然就是f[u]=max(Σf[v],0),p[u]=max(max(p[v]),f[u]) 然后看动态的部分,设g是不算重儿子的f,然后每条链上的真实f值要用一棵线段树维护g来得到,具体形式是f[u]=max(g[v]+f[hs[v]],0),是一个最长连续子序列的形式,

Codeforces 165D Beard Graph 边权树剖+树状数组

Beard Graph 题意:给你一颗由n个结点组成的树,支持以下操作:1 i:将第i条边染成黑色(保证此时该边是白色),2 i:将第i条边染成白色(保证此时该边是黑色),3 a b:找出a,b两点之间只由黑边组成的最短路径. 思路:树链剖分+树状数组,把每条边的权值放到它指向的点中去,初始全为黑边,黑边权值为1,白边权值为-inf,黑边变白边,将点权增加-inf,白边变黑边点权增加inf,因为不可能白边边白边,所以可以这样做,查询的时候要减去2个点的最近公共祖先的点权,最近公共祖先可通过树剖的

最近公共祖先(LCA)问题的树剖实现 (模板)

我来存个档,防止忘记!2333 传送门:https://daniu.luogu.org/problem/show?pid=3379 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询问的个数和树根结点的序号. 接下来N-1行每行包含两个正整数x.y,表示x结点和y结点之间有一条直接连接的边(数据保证可以构成树). 接下来M行每行包含两个正整数a.b,表示询问a结点和b结点的最近公共祖先. 输

LCA[倍增][树剖][tarjan]

LCA:最近公共祖先 倍增: 1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<vector> 5 using namespace std; 6 #define N 105 7 int deep[N],dad[N][21]; 8 vector<int>vec[N]; 9 int lca(int x,int y) { 10 if(deep[x]>dee