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;
}