树上修改莫队算法
非常好的一道题,其实应该把部分分都写一次
前30分是送的
50分是最普通的莫队算法
70分是clj的选择,也就是树上不修改莫队
100分是树上修改莫队
其实我昨天晚上睡觉的时候意识到第二天要很早起来写糖果公园但是还是没有意识到这个题的恶心之处,第一次写完貌似有9k。。。
然后赶紧缩,最后好不容易到了7k左右,不记得了。。。
很经典很神的算法,只不过因为程序太长了所以我不得不采用和标程对拍中间结果的办法来检查程序,如果这是在考场上那么我会毫不犹豫的选择哪个50分
不得不说艾神的题很复杂,而且我也看了vfk的题解。。。。
就这么多吧,似乎看了题解的人没资格讲做法,具体的去看vfk
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define Size (int)pow(n,2.0/3)
#define MAX 200010
#define ll long long
using namespace std;
int n,m,k,ind,BlockSize=0;
int cnt[MAX],pos[MAX];
int deep[MAX];
ll ans;
bool vis[MAX]={0};
int father[MAX],f[MAX][20];
int logg[MAX];
int wait[MAX],waitting=0;
ll val1[MAX],val2[MAX];
vector<int>candy[MAX];
vector<int>edge[MAX];
vector<int>::iterator now[MAX];
struct wbysr_change
{
int a,b;
}op[MAX];
struct wbysr
{
int l,r,id;
ll ans;
}ask[MAX];
void debug_()
{
for(int i=1;i<=n;i++)
{
printf("----%d\n",i);
for(int j=0;j<edge[i].size();j++)
printf("%d ",edge[i][j]);
printf("\n");
for(int j=0;j<candy[i].size();j++)
printf("%d ",candy[i][j]);
printf("\n");
}
//printf("debug done\n");
for(int i=1;i<=n;i++)
printf("%d %d\n",i,pos[i]);
}
int dfs(int x)
{
// printf("fuck %d\n",x);
int sum=0;
/*for(int i=0;i<edge[x].size();i++)
if(!deep[i])
{
father[i]=x;
deep[i]=deep[x]+1;
f[i][0]=x;
for(int j=1;j<=18;j++)
f[i][j]=f[f[i][j-1]][j-1];
sum+=dfs(i);
if(sum>=Size)
{
BlockSize++;
while(sum--)
pos[wait[waitting--]]=BlockSize;
sum=0;
}
}*/
///*
for(vector<int>::iterator i=edge[x].begin();i!=edge[x].end();i++)
if(0==deep[*i])
{
father[*i]=x;
deep[*i]=deep[x]+1;
f[*i][0]=x;
for(int j=1;j<=18;j++)
f[*i][j]=f[f[*i][j-1]][j-1];
sum+=dfs(*i);
if(sum>=Size)
{
BlockSize++;
while(sum--)
pos[wait[waitting--]]=BlockSize;//printf("ooooooooooo%d %d\n",wait[waitting+1],pos[wait[waitting+1]]);
sum=0;
}
}//*/
wait[++waitting]=x;
return ++sum;
}
bool sort_ask(wbysr a1,wbysr a2)
{
if(pos[a1.l]!=pos[a2.l])
return pos[a1.l]<pos[a2.l];
else
if(pos[a1.r]!=pos[a2.r])
return pos[a1.r]<pos[a2.r];
return a1.id<a2.id;
}
void init()
{
scanf("%d%d%d",&n,&m,&k);
//read
for(int i=1;i<=m;i++)
scanf("%lld",&val1[i]);
for(int i=1;i<=n;i++)
scanf("%lld",&val2[i]);
for(int i=1,a1,a2;i<=n-1;i++)
{
scanf("%d%d",&a1,&a2);
edge[a1].push_back(a2);
edge[a2].push_back(a1);
}
for(int i=1,w;i<=n;i++)
{
scanf("%d",&w);
candy[i].push_back(w);
}
ind=0;
for(int i=1,c;i<=k;i++)
{
scanf("%d",&c);
if(0==c)
{
scanf("%d%d",&op[i].a,&op[i].b);
candy[op[i].a].push_back(op[i].b);
}
else
{
ind++;
scanf("%d%d",&ask[ind].l,&ask[ind].r);
ask[ind].id=i;
// printf("====================%d %d\n",ask[ind].l,ask[ind].r);
}
}
// printf("sfddddddddd\n");
//before done
for(int i=1;i<=n;i++)
now[i]=candy[i].begin();
deep[1]=1;
dfs(1);
// printf("888888888888888888888\n");
// while(waitting)
// pos[wait[waitting--]]=BlockSize;
for(int i=2;i<=n;i++)
logg[i]=logg[i-1]+(i==(i&-i));
// for(int i=1;i<=ind;i++)
// if(pos[ask[i].l]>pos[ask[i].r])
// swap(ask[i].l,ask[i].r);
sort(ask+1,ask+1+ind,sort_ask);
//debug();
// for(int i=1;i<=ind;i++)
// printf("++++++++++++++++++%d %d\n",ask[i].l,ask[i].r);
}
void xor_point(int x)
{
if(vis[x])
{
int c=*now[x];
ans-=val1[c]*val2[cnt[c]];
cnt[c]--;
vis[x]=0;
//ans+=val1[c]*val2[cnt[c]];
}
else
{
int c=*now[x];
cnt[c]++;
ans+=val1[c]*val2[cnt[c]];
vis[x]=1;
//ans-=val1[c]*val2[cnt[c]];
}
return;
}
void xor_path(int a,int b)
{
if(deep[a]<deep[b])
swap(a,b);
while(deep[a]!=deep[b])
{
xor_point(a);
a=father[a];
}
while(a!=b)
{
xor_point(a);
xor_point(b);
a=father[a];
b=father[b];
}
}
int LCA(int a,int b)
{
//printf("LCA begin\n");
if(deep[a]<deep[b])
swap(a,b);
for(int i=logg[deep[a]];i>=0;i--)
if(deep[f[a][i]]>=deep[b])
a=f[a][i];
if(a==b)
return a;
for(int i=logg[deep[a]];i>=0;i--)
if(f[a][i]!=f[b][i])
{
a=f[a][i];
b=f[b][i];
}
//printf("LCA end\n");
return father[a];
}
ll work(int a,int b)
{
int lca=LCA(a,b);
//printf("^^^^^^^^^^^^^^^^^^^^^^^^^^^^^%d %d %d\n",a,b,lca);
xor_point(lca);
ll tot=ans;
// printf("%lld\n",tot);
xor_point(lca);
return tot;
}
void captail_mo()
{
for(int i=1,l=1,r=1,time=0;i<=ind;i++)
{
// printf("%d %d %d %d %d\n",ask[i].id,ask[i].l,ask[i].r,l,r);
while(time<ask[i].id)
{
int p=op[++time].a;
if(!p)
continue;
bool flag=vis[p];
if(flag)
xor_point(p);
++now[p];
if(flag)
xor_point(p);
}
while(time>ask[i].id)
{
int p=op[time--].a;
if(!p)
continue;
bool flag=vis[p];
if(flag)
xor_point(p);
now[p]--;
if(flag)
xor_point(p);
}
xor_path(l,ask[i].l);
xor_path(r,ask[i].r);
l=ask[i].l;
r=ask[i].r;
// printf("MO\n");
ask[i].ans=work(l,r);
}
}
bool cmp_end(wbysr a1,wbysr a2)
{
return a1.id<a2.id;
}
void print()
{
sort(ask+1,ask+1+ind,cmp_end);
for(int i=1;i<=ind;i++)
printf("%lld\n",ask[i].ans);
return;
}
void da()
{
for(int i=1;i<=k;i++)
if(ask[i].l>ask[i].r)
swap(ask[i].l,ask[i].r);
return;
}
int main()
{
init();
//printf("------------------init\n");
// da();
captail_mo();
//printf("------------------captail_mo");
print();
return 0;
}