n(n<=1e5)个点的树,第i条边有u,v,c,d,u和v为边的两端,c为色号,d为边长
q(q<=1e5)个询问,第j次询问x,y,u,v,即把色号为x的所有边权都改成y之后,询问u到v的距离
https://atcoder.jp/contests/abc133/submissions/6298312
离线,把所有颜色为i的树边加到col[i]里,把所有颜色为j的询问加到color[j]里,
预处理点欧拉序,边欧拉序,用RMQ来解决LCA,sum[]维护当前点到根的链和
处理颜色i的询问时,ans=两条链之和-两条链上原颜色i树边之和+两条链上颜色i的边的个数*新改的值
做法,先把i的树边的条数插到bit1上,边权插到树状数组bit2上,
bit1中统计两条链上颜色i的边的个数,乘上新改的值v,从答案中减去
bit2中统计一下两条链上原颜色i树边之和,加到答案中
统计完之后,在BIT里把刚插入的颜色对应的边删掉,从而处理下一种颜色
本来在考虑,边是离散的,该如何解决,
现在了解到,边在欧拉序中也是对应一段区间的;像树剖一样,把边给远根节点,其欧拉序同远端节点
第i条边(连接u和v,且v是远根节点),入的时间戳同ID[v],出的时间戳同v出的时间戳
那么由于v出了之后,下一个出的就是u,这里不妨+1,变闭区间为开区间,i实际存在的为[in[i],out[i])
#include
#define pb push_back
using namespace std;
const int N=1e5+10;
const int lg=18;
int n,q;
int a,b,c,d,y,U,V,fa,ID;
int tmp,num,len1,len2;
int pos[N],ans[N],sum[N];//欧拉序中对应编号 答案 链上的和
int bit1[N*2],bit2[N*2];//树按颜色建一棵 按查询建一棵
int dep[N],dis[N];//点的深度 实际边边权
int head[N],v[N*2],nex[N*2],id[N*2],cnt;
int in[N],out[N];
int dfn[N*2],tot;
int dp[N*2][lg];
//欧拉序 dfn点戳 in out边戳 第i条边[in,out)
struct query{int id,y,u,v;};
vectorcol[N];//把树边放入对应颜色
vectorcolor[N];//把询问放入对应颜色
int mn(int u,int v){if(dep[u]0;i-=i&-i)ans+=tr[i];return ans;}
void dfs(int u,int fa,int d)
{
dfn[++tot]=u;
pos[u]=tot;
dep[u]=d;
for(int i=head[u];i;i=nex[i])
{
int to=v[i],num=id[i],w=dis[num];//边的真实编号
if(to==fa)continue;
in[num]=tot+1;//归远端节点 即下一个搜的节点
sum[to]=sum[u]+w;
dfs(to,u,d+1);
dfn[++tot]=u;
out[num]=tot;
}
}
void init(int up)
{
for(int i=1;i<=up;++i)
dp[i][0]=dfn[i];
for(int len=1;(1<r)swap(l,r);
int k=log(r-l+1)/log(2);
return mn(dp[l][k],dp[r-(1<