Hillan大佬神奇的idea
求出树的dfs序,只要能处理加边和删边操作就行了
令加入的边为 (x,y) ( x , y ) ,不妨设 x x 是 的父亲,令 z z 为 所在联通块的根,那么 x x 到 路径上的点权值都加上了 y y <script type="math/tex" id="MathJax-Element-24">y</script> 所在的联通块大小
这可以用dfs序维护
删边就一样了
用线段树维护,只要就可以可持久化了…
调了一天发现边的颜色没有可持久化…
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <assert.h>
#include <cstdlib>
using namespace std;
typedef long long ll;
const int N=240010,L=1000000;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void read(int &x){
char c=nc(); x=0;
for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc());
}
int n,q,lst,p[N],lg2[N];
int st[N][25];
inline void Pre(){
for(int i=1;i<=lst;i++) lg2[i]=lg2[i-1]+((1<<lg2[i-1]+1)==i);
int t=lg2[lst];
for(int i=1;i<=lst;i++) st[i][0]=p[i];
for(int k=1;k<=t;k++)
for(int i=1;i+(1<<k)-1<=lst;i++)
st[i][k]=min(st[i][k-1],st[i+(1<<k-1)][k-1]);
}
inline int Min(int l,int r){
int t=lg2[r-l+1];
return min(st[l][t],st[r-(1<<t)+1][t]);
}
namespace S{
int cnt,ls[N*100],rs[N*100];
int tot[N*100],mn[N*100];
inline int Min(int x,int l,int r){
if(!x) return ::Min(l,r)-p[l-1];
return mn[x];
}
inline int Tot(int g,int l,int r){
if(!g) return p[r]-p[l-1];
return tot[g];
}
pair<int,int> find(int g,int l,int r,int L,int R,int x){
if(L==R) return make_pair(x+Min(g,L,R)<=0?L:-1,x+Tot(g,L,R));
if(l==L && r==R){
int mid=L+R>>1;
if(Min(g,L,R)>-x) return make_pair(-1,x+Tot(g,L,R));
if(Min(ls[g],L,mid)<=-x) return find(ls[g],l,mid,L,mid,x);
return find(rs[g],mid+1,r,mid+1,R,x+Tot(ls[g],L,mid));
}
int mid=L+R>>1;
if(r<=mid) return find(ls[g],l,r,L,mid,x);
else if(l>mid) return find(rs[g],l,r,mid+1,R,x);
pair<int,int> A=find(ls[g],l,mid,L,mid,x);
if(~A.first) return A;
return find(rs[g],mid+1,r,mid+1,R,x+A.second);
}
int Query(int g,int l,int r,int L,int R){
if(!g) return p[r]-p[l-1];
if(l==L && r==R) return tot[g];
int mid=L+R>>1;
if(r<=mid) return Query(ls[g],l,r,L,mid);
else if(l>mid) return Query(rs[g],l,r,mid+1,R);
else return Query(ls[g],l,mid,L,mid)+Query(rs[g],mid+1,r,mid+1,R);
}
void Add(int &g,int x,int L,int R,int y){
int k=g; g=++cnt; ls[g]=ls[k]; rs[g]=rs[k];
tot[g]=Tot(k,L,R)+y;
if(L==R) return mn[g]=tot[g],void();
int mid=L+R>>1;
if(x<=mid) Add(ls[g],x,L,mid,y); else Add(rs[g],x,mid+1,R,y);
mn[g]=min(Tot(ls[g],L,mid)+Min(rs[g],mid+1,R),Min(ls[g],L,mid));
}
}
int R[N];
int u[N],v[N],c[N],dpt[N],bg[N],ed[N],bl[N];
namespace C{
int cnt,ls[N*100],rs[N*100],root[N*100];
ll sum[N*100];
ll find(int g,int l,int r,int c,int x){
if(l==r) return S::find(root[g],x,lst,1,lst,0).first;
int mid=l+r>>1;
if(c<=mid) return find(ls[g],l,mid,c,x);
else return find(rs[g],mid+1,r,c,x);
}
int Query(int g,int l,int r,int L,int R,int c){
if(L==R) return S::Query(root[g],l,r,1,lst);
int mid=L+R>>1;
if(c<=mid) return Query(ls[g],l,r,L,mid,c);
else return Query(rs[g],l,r,mid+1,R,c);
}
void add(int &g,int x,int l,int r,ll y){
int k=g; g=++cnt; ls[g]=ls[k]; rs[g]=rs[k];
sum[g]=sum[k]+y; root[g]=root[k];
if(l==r) return ;
int mid=l+r>>1;
if(x<=mid) add(ls[g],x,l,mid,y); else add(rs[g],x,mid+1,r,y);
}
ll query(int g,int l,int r,int L,int R){
if(l==L && r==R) return sum[g];
int mid=L+R>>1;
if(r<=mid) return query(ls[g],l,r,L,mid);
else if(l>mid) return query(rs[g],l,r,mid+1,R);
else return query(ls[g],l,mid,L,mid)+query(rs[g],mid+1,r,mid+1,R);
}
void Add(int &g,int c,int x,int L,int R,int y){
int k=g; g=++cnt; ls[g]=ls[k]; rs[g]=rs[k]; root[g]=root[k]; sum[g]=sum[k];
if(L==R) return S::Add(root[g],x,1,lst,y);
int mid=L+R>>1;
if(c<=mid) Add(ls[g],c,x,L,mid,y);
else Add(rs[g],c,x,mid+1,R,y);
}
}
int G[N],cnt;
struct edge{
int t,nx;
}E[N<<1];
inline void addedge(int x,int y){
E[++cnt].t=y; E[cnt].nx=G[x]; G[x]=cnt;
E[++cnt].t=x; E[cnt].nx=G[y]; G[y]=cnt;
}
void dfs(int x,int f){
dpt[x]=dpt[f]+1; bg[x]=++lst; p[lst]++;
for(int i=G[x];i;i=E[i].nx)
if(E[i].t!=f) dfs(E[i].t,x);
ed[x]=++lst; bl[lst]=x; p[lst]--;
}
ll calc(int x){ return 1LL*x*(x-1)/2; }
inline void addc(int &R,int x,int y,int c){
int _x,_y,cur;
if(dpt[x]>dpt[y]) swap(x,y);
_x=bl[C::find(R,1,L,c,bg[x])];
_y=y;
int sx=C::Query(R,bg[_x],ed[_x]-1,1,L,c),sy=C::Query(R,bg[_y],ed[_y]-1,1,L,c);
C::Add(R,c,ed[_y],1,L,sy); C::Add(R,c,ed[_x],1,L,-sy);
C::add(R,c,1,L,calc(sx+sy)-calc(sx)-calc(sy));
}
inline void delc(int &R,int x,int y,int c){
int _x,_y,cur;
if(dpt[x]>dpt[y]) swap(x,y);
_x=bl[C::find(R,1,L,c,bg[x])];
_y=y;
int sx=C::Query(R,bg[_x],ed[_x]-1,1,L,c),sy=C::Query(R,bg[_y],ed[_y]-1,1,L,c);
C::Add(R,c,ed[_y],1,L,-sy); C::Add(R,c,ed[_x],1,L,sy);
C::add(R,c,1,L,calc(sx-sy)+calc(sy)-calc(sx));
}
int rt[N];
namespace ED{
int cnt,ls[N*30],rs[N*30],c[N*30];
void cg(int &g,int x,int l,int r,int cc){
int k=g; g=++cnt; ls[g]=ls[k]; rs[g]=rs[k];
if(l==r) return c[g]=cc,void("%%%vector");
int mid=l+r>>1;
if(x<=mid) cg(ls[g],x,l,mid,cc); else cg(rs[g],x,mid+1,r,cc);
}
int get(int g,int x,int l,int r){
if(l==r) return c[g];
int mid=l+r>>1;
if(x<=mid) return get(ls[g],x,l,mid);
else return get(rs[g],x,mid+1,r);
}
}
int flg[N],ct;
int main(){
read(n);
for(int i=1;i<n;i++){
read(u[i]),read(v[i]),read(c[i]),addedge(u[i],v[i]);
ED::cg(rt[0],i,1,n,c[i]);
}
dfs(1,0); //C::Build();
for(int i=1;i<=lst;i++) p[i]+=p[i-1]; Pre();
for(int i=1;i<n;i++) addc(R[0],u[i],v[i],c[i]);
read(q);
for(int k=1;k<=q;k++){
R[k]=R[k-1]; rt[k]=rt[k-1];
int opt; read(opt);
if(opt==1){
flg[++ct]=k;
int i; read(i);
c[i]=ED::get(rt[k],i,1,n);
delc(R[k],u[i],v[i],c[i]);
read(c[i]); ED::cg(rt[k],i,1,n,c[i]);
addc(R[k],u[i],v[i],c[i]);
}
else if(opt==2){
int l,r; read(l); read(r);
printf("%lld\n",C::query(R[k],l,r,1,L));
}
else if(opt==3){
int i; read(i); c[i]=ED::get(rt[k],i,1,n);
int x=dpt[u[i]]<dpt[v[i]]?u[i]:v[i],_x;
_x=bl[C::find(R[k],1,L,c[i],bg[x])];
printf("%lld\n",calc(C::Query(R[k],bg[_x],ed[_x]-1,1,L,c[i])));
}
else{
int i; read(i); R[k]=R[flg[i]-1]; rt[k]=rt[flg[i]-1];
}
}
return 0;
}