给定一颗n个结点的树。每个结点有一种颜色。颜色种类为m。
一条路径的价值定义为
这是树上莫队,我们接下来只讨论序列莫队,树上莫队可以转化为序列莫队。
带修改莫队怎么做呀?
分块大小设为 n13
对于每个询问,用三元组表示(l,r,x)表示询问区间为[l,r]然后是在第x次修改操作后。
以左端点所在块为第一关键字,右端点所在块为第二关键字,已经经过的修改次数为第三关键字排序。
那么就和二维的莫队差不多,你只是需要额外兹瓷修改操作与撤销修改操作(其实都是修改操作)
可以证明总共的复杂度是 o(n53)
本题我的分块大小是取了1750。
#include<cstdio>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn=100000+10;
struct dong{
int l,r,x,id,w;
bool p;
};
int belong[maxn*2];
bool operator <(dong a,dong b){
if (belong[a.l]<belong[b.l]) return 1;
else if (belong[a.l]==belong[b.l]&&belong[a.r]<belong[b.r]) return 1;
else if (belong[a.l]==belong[b.l]&&belong[a.r]==belong[b.r]&&a.x<b.x) return 1;
else return 0;
}
dong ask[maxn];
int v[maxn],w[maxn],cnt[maxn],fi[maxn],la[maxn],a[maxn*2],c[maxn];
int h[maxn],go[maxn*2],next[maxn*2],b[maxn][3];
int f[maxn][25],d[maxn];
ll ans[maxn];
bool bz[maxn];
int i,j,k,l,r,x,t,n,m,q,block,tot,top,num,sum;
ll now;
void add(int x,int y){
go[++tot]=y;
next[tot]=h[x];
h[x]=tot;
}
void dfs(int x,int y){
fi[x]=++top;
a[top]=x;
d[x]=d[y]+1;
f[x][0]=y;
int t=h[x];
while (t){
if (go[t]!=y) dfs(go[t],x);
t=next[t];
}
la[x]=++top;
a[top]=x;
}
int lca(int x,int y){
int j;
if (d[x]<d[y]) swap(x,y);
if (d[x]!=d[y]){
j=floor(log(d[x]-d[y])/log(2));
while (j>=0){
if (d[f[x][j]]>d[y]) x=f[x][j];
j--;
}
x=f[x][0];
}
if (x==y) return x;
j=floor(log(d[x])/log(2));
while (j>=0){
if (f[x][j]!=f[y][j]){
x=f[x][j];
y=f[y][j];
}
j--;
}
return f[x][0];
}
void change(int x){
bz[x]^=1;
if (bz[x]){
cnt[c[x]]++;
now+=(ll)w[cnt[c[x]]]*v[c[x]];
}
else{
now-=(ll)w[cnt[c[x]]]*v[c[x]];
cnt[c[x]]--;
}
}
void in(int x){
if (bz[b[x][2]]){
now-=(ll)w[cnt[b[x][0]]]*v[b[x][0]];
cnt[b[x][0]]--;
cnt[b[x][1]]++;
now+=(ll)w[cnt[b[x][1]]]*v[b[x][1]];
}
c[b[x][2]]=b[x][1];
}
void out(int x){
if (bz[b[x][2]]){
now-=(ll)w[cnt[b[x][1]]]*v[b[x][1]];
cnt[b[x][1]]--;
cnt[b[x][0]]++;
now+=(ll)w[cnt[b[x][0]]]*v[b[x][0]];
}
c[b[x][2]]=b[x][0];
}
int main(){
scanf("%d%d%d",&n,&m,&q);
fo(i,1,m) scanf("%d",&v[i]);
fo(i,1,n) scanf("%d",&w[i]);
fo(i,1,n-1){
scanf("%d%d",&j,&k);
add(j,k);add(k,j);
}
dfs(1,0);
fo(j,1,floor(log(n)/log(2)))
fo(i,1,n)
f[i][j]=f[f[i][j-1]][j-1];
fo(i,1,n) scanf("%d",&c[i]);
fo(i,1,q){
scanf("%d",&t);
if (!t){
scanf("%d%d",&j,&k);
b[++num][0]=c[j];
b[num][1]=c[j]=k;
b[num][2]=j;
}
else{
scanf("%d%d",&j,&k);
t=lca(j,k);
if (t==j||t==k){
ask[++sum].p=0;
l=fi[j];r=fi[k];
if (l>r) swap(l,r);
}
else{
ask[++sum].p=1;
ask[sum].w=t;
if (fi[j]>fi[k]) swap(j,k);
l=la[j];r=fi[k];
}
ask[sum].l=l;ask[sum].r=r;
ask[sum].id=sum;
ask[sum].x=num;
}
}
fd(i,num,1) c[b[i][2]]=b[i][0];
block=1750;
fo(i,1,2*n) belong[i]=(i-1)/block+1;
sort(ask+1,ask+sum+1);
l=r=1;x=0;
change(a[1]);
fo(i,1,sum){
while (x>ask[i].x){
out(x);
x--;
}
while (x<ask[i].x){
x++;
in(x);
}
while (l>ask[i].l){
l--;
change(a[l]);
}
while (l<ask[i].l){
change(a[l]);
l++;
}
while (r<ask[i].r){
r++;
change(a[r]);
}
while (r>ask[i].r){
change(a[r]);
r--;
}
if (ask[i].p) change(ask[i].w);
ans[ask[i].id]=now;
if (ask[i].p) change(ask[i].w);
}
fo(i,1,sum) printf("%lld\n",ans[i]);
}