21.7.13 t3

tag:虚树,树剖,点分治,BIT


先不管修改操作,这个 \(\sum k\le 3e5\),很虚树。

然后统计合法路径数,很点分。

所以就虚树上点分治了,注意虚树上一条边有两个权值 \(dis,len\)

这部分复杂度 \(O(nlogn+nlog^2n)\)

然后考虑路径加操作,随便维护一下。

如果用树剖直接维护的话,修改、建树和点分都是 \(O(nlog^2n)\),已经能通过本题了。

融合怪


#include<bits/stdc++.h>
using namespace std;
 
template<typename T>
inline void Read(T &n){
    char ch; bool flag=false;
    while(!isdigit(ch=getchar()))if(ch=='-')flag=true;
    for(n=ch^48;isdigit(ch=getchar());n=(n<<1)+(n<<3)+(ch^48));
    if(flag)n=-n;
}
 
typedef long long ll;
enum{
    MAXN = 300005
};
 
int n, m;
 
struct _{
    int nxt, to, len;
    _(int nxt=0, int to=0, int len=0):nxt(nxt),to(to),len(len){}
}edge[MAXN<<1];
int fst[MAXN], tot;
 
inline void Add_Edge(int f, int t, int len){
    edge[++tot] = _(fst[f], t, len); fst[f] = tot;
    edge[++tot] = _(fst[t], f, len); fst[t] = tot;
}
 
int sz[MAXN], son[MAXN], fa[MAXN], top[MAXN], dep[MAXN], dfn[MAXN], loc[MAXN], a[MAXN], cnt;
void dfs1(int x, int y){
    dep[x] = dep[y]+1; sz[x] = 1; fa[x] = y;
    for(int u=fst[x]; u; u=edge[u].nxt){
        int v=edge[u].to;
        if(v==y) continue;
        a[v] = edge[u].len;
        dfs1(v,x);
        sz[x] += sz[v];
        if(sz[v] > sz[son[x]]) son[x] = v;
    }
}
 
void dfs2(int x, int y){
    top[x] = y; dfn[++cnt] = x; loc[x] = cnt;
    if(son[x]) dfs2(son[x],y);
    for(int u=fst[x]; u; u=edge[u].nxt){
        int v=edge[u].to;
        if(v==son[x] or v==fa[x]) continue;
        dfs2(v,v);
    }
}
 
struct node{
    ll add, sum; int sz;
    #define add(x) t[x].add
    #define sz(x) t[x].sz
    #define sum(x) t[x].sum
}t[MAXN<<2];
inline int lc(int x){return x<<1;}
inline int rc(int x){return x<<1|1;}
 
inline void Push_Up(int x){sum(x) = sum(lc(x))+sum(rc(x));}
 
inline void Add(int x, ll add){
    add(x) += add;
    sum(x) += 1ll*sz(x)*add;
}
 
inline void Push_Down(int x){
    if(add(x))
        Add(lc(x),add(x)),
        Add(rc(x),add(x)),
        add(x) = 0;
}
 
void Build(int x, int head, int tail){
    sz(x) = tail-head+1;
    if(head==tail) return sum(x) = a[dfn[head]], void();
    int mid = head+tail >> 1;
    Build(lc(x),head,mid); Build(rc(x),mid+1,tail);
    Push_Up(x);
}
 
void Add(int x, int head, int tail, int l, int r, ll add){
    if(l<=head and tail<=r) return Add(x,add);
    Push_Down(x);
    int mid = head+tail >> 1;
    if(l<=mid) Add(lc(x),head,mid,l,r,add);
    if(mid<r) Add(rc(x),mid+1,tail,l,r,add);
    Push_Up(x);
}
 
ll Query(int x, int head, int tail, int l, int r){
    if(l<=head and tail<=r) return sum(x);
    Push_Down(x);
    int mid = head+tail >> 1; ll res=0;
    if(l<=mid) res += Query(lc(x),head,mid,l,r);
    if(mid<r) res += Query(rc(x),mid+1,tail,l,r);
    return res;
}
 
inline void Add(int u, int v, ll add){
    while(top[u]!=top[v]){
        if(dep[top[u]]<dep[top[v]]) swap(u,v);
        Add(1,1,n,loc[top[u]],loc[u],add);
        u = fa[top[u]];
    }
    if(loc[u]==loc[v]) return;
    if(loc[u]>loc[v]) swap(u,v);
    Add(1,1,n,loc[u]+1,loc[v],add);
}
 
inline ll Query(int u, int v){
    ll res = 0;
    while(top[u]!=top[v]){
        if(dep[top[u]]<dep[top[v]]) swap(u,v);
        res += Query(1,1,n,loc[top[u]],loc[u]);
        u = fa[top[u]];
    }
    if(loc[u]==loc[v]) return res;
    if(loc[u]>loc[v]) swap(u,v);
    res += Query(1,1,n,loc[u]+1,loc[v]);
    return res;
}
 
inline int lca(int u, int v){
    while(top[u]!=top[v]){
        if(dep[top[u]]<dep[top[v]]) swap(u,v);
        u = fa[top[u]];
    }
    return dep[u]<dep[v]?u:v;
}
 
namespace VT{
    int n, L, R, k;
    ll ans;
 
    struct BIT{
        #define lowbit(x) (x&-x)
        ll t[MAXN];
        inline void Add(int x, ll k){for(;x<=::n;x+=lowbit(x))t[x]+=k;}
        inline ll Query(int x){ll res=0;for(;x;x-=lowbit(x))res+=t[x];return res;}
        inline ll Query(int l, int r){return l<=r?Query(r)-Query(l-1):0;}
        #undef lowbit
    }t1,t2;
 
    struct _{
        int nxt, to, dis; ll len;
        _(int nxt=0, int to=0, int dis=0, ll len=0):nxt(nxt),to(to),dis(dis),len(len){}
    }edge[MAXN<<1];
    int fst[MAXN], tot;
 
    inline void Add_Edge(int f, int t, int dis, ll len){
        // printf("Add %d %d %d %lld\n",f,t,dis,len);
        edge[++tot] = _(fst[f], t, dis, len); fst[f] = tot;
        edge[++tot] = _(fst[t], f, dis, len); fst[t] = tot;
    }
 
    inline void link(int u, int v){Add_Edge(u,v,abs(dep[u]-dep[v]),Query(u,v));}
 
    char vis[MAXN], Vis[MAXN], mk[MAXN];
    inline void clear(int x){fst[x] = Vis[x] = mk[x] = 0; n++;}
 
    int Center, Size, Weight, sz[MAXN];
    void Get_Center(int x){
        vis[x] = true; sz[x] = 1;
        int res = 0;
        for(int u=fst[x]; u; u=edge[u].nxt){
            int v=edge[u].to;
            if(Vis[v] or vis[v]) continue;
            Get_Center(v);
            sz[x] += sz[v];
            res = max(res,sz[v]);
        }
        res = max(res,Size-sz[x]);
        if(res < Weight) Weight = res, Center = x;
        vis[x] = false;
    }
 
    struct ele{int x, dis; ll len;}p[MAXN]; int pcnt;
 
    void dfs(int x, int dis, ll len){
        if(dis>R) return;
        vis[x] = true;
        sz[x] = 1;
        if(mk[x]) p[++pcnt] = (ele){x,dis,len};
        for(int u=fst[x]; u; u=edge[u].nxt){
            int v=edge[u].to;
            if(Vis[v] or vis[v]) continue;
            dfs(v,dis+edge[u].dis,len+edge[u].len);
            sz[x] += sz[v];
        }
        vis[x] = false;
    }
 
    inline ll Query(ele x){
        if(L<=x.dis and x.dis<=R and mk[Center]) ans += x.len;
        int l = max(1,L-x.dis), r = R-x.dis;
        return t1.Query(l,r)+1ll*t2.Query(l,r)*x.len;
    }
 
    void solve(int x){
        Weight = Size = sz[x]; Get_Center(x); Vis[x=Center] = true;
        // printf("solve %d\n",x);
 
        pcnt=0;
        for(int u=fst[x]; u; u=edge[u].nxt){
            int v=edge[u].to;
            if(Vis[v]) continue;
            int prv=pcnt+1;
            dfs(v,edge[u].dis,edge[u].len);
            // for(int i=prv; i<=pcnt; i++) printf("%d %d %lld\n",p[i].x,p[i].dis,p[i].len);
            for(int i=prv; i<=pcnt; i++) ans += Query(p[i]);
            for(int i=prv; i<=pcnt; i++) t1.Add(p[i].dis,p[i].len), t2.Add(p[i].dis,1);
        }
        for(int i=1; i<=pcnt; i++) t1.Add(p[i].dis,-p[i].len), t2.Add(p[i].dis,-1);
 
        for(int u=fst[x]; u; u=edge[u].nxt){
            int v=edge[u].to;
            if(Vis[v]) continue;
            solve(v);
        }
    }
 
    int q[MAXN], top, a[MAXN];
    inline bool cmp(const int &u, const int &v){return loc[u]<loc[v];}
 
    inline void solve(){
        Read(L); Read(R); Read(k);
        assert(L<=R);
        ans = n = tot = 0;
        for(int i=1; i<=k; i++) Read(a[i]);
        sort(a+1,a+k+1,cmp); clear(q[top=1]=1);
        for(int i=1; i<=k; i++){
            int u = lca(q[top],a[i]);
            if(u!=q[top]){
                while(dep[u]<=dep[q[top-1]]) link(q[top-1],q[top]), top--;
                if(q[top]!=u) clear(u), link(q[top],u), q[top] = u;
            }
            if(q[top]!=a[i]) q[++top] = a[i], clear(a[i]);
        }
        while(top>1) link(q[top],q[top-1]), top--;
        for(int i=1; i<=k; i++) mk[a[i]] = true;
        sz[1] = n; solve(1);
        for(int i=1; i<=k; i++) mk[a[i]] = false;
        cout<<ans<<'\n';
    }
}
using VT::solve;
 
int main(){
    // freopen("3.in","r",stdin);
    // freopen("3.out","w",stdout);
    Read(n); Read(m);
    for(int i=1; i<n; i++){
        int f, t; ll len;
        Read(f); Read(t); Read(len);
        Add_Edge(f,t,len);
    }
    dfs1(1,0); dfs2(1,1);
    Build(1,1,n);
    for(int i=1; i<=m; i++){
        int opt; Read(opt);
        if(opt==1){
            int u, v; ll w;
            Read(u); Read(v); Read(w);
            Add(u,v,w);
        }
        if(opt==2) solve();
    }
    return 0;
}
posted @ 2021-07-13 15:13  oisdoaiu  阅读(23)  评论(0编辑  收藏  举报