3052: [wc2013]糖果公园
Time Limit: 200 Sec Memory Limit: 512 MBSubmit: 1274 Solved: 642
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
Sample Input
Sample Output
84
131
27
84
131
27
84
HINT
这就是传说中的树上莫队
先讲一讲树上莫队大法
算法流程:
树分块、询问排序、莫队大法
先树分块
我用的是“王室联邦分块法(我的块大小参考了hzwer)”(当然其他的也可以)详见BZOJ 1086: [SCOI2005]王室联邦 树分块
询问排序以路径起始点、终点所在的块为第一、二关键字,时间为第三关键字
之后就像带修改莫队一样搞
那么,如何实现树上路径的转移呢
这里粘一点东西 嘻嘻
用S(v, u)代表 v到u的路径上的结点的集合
用root来代表根结点,用lca(v, u)来代表v、u的最近公共祖先
那么S(v, u) = S(root, v) xor S(root, u) xor lca(v, u)
其中xor是集合的对称差
简单来说就是节点出现两次消掉
lca很讨厌,于是再定义
T(v, u) = S(root, v) xor S(root, u)
观察将curV移动到targetV前后T(curV, curU)变化
T(curV, curU) = S(root, curV) xor S(root, curU)
T(targetV, curU) = S(root, targetV) xor S(root, curU)
取对称差:
T(curV, curU) xor T(targetV, curU)= (S(root, curV) xor S(root, curU)) xor (S(root, targetV) xor S(root, curU))
由于对称差的交换律、结合律:
T(curV, curU) xor T(targetV, curU)= S(root, curV) xorS(root, targetV)
两边同时xor T(curV, curU):
T(targetV, curU)= T(curV, curU) xor S(root, curV) xor S(root, targetV)
发现最后两项很爽……哇哈哈
T(targetV, curU)= T(curV, curU) xor T(curV, targetV)
(有公式恐惧症的不要走啊 T_T)
也就是说,更新的时候,xor T(curV, targetV)就行了。
即,对curV到targetV路径(除开lca(curV, targetV))上的结点,将它们的存在性取反即可。
所以对于路径(u,v)向(x,y)转移时
(x,y)=(u,v) xor (u,x) xor (v,y)
(lca自己乱搞)
之后 就可以A掉这道题了
括弧
讲真。。lca从来没写对过(链剖版除外)
花了1个小时 只为了lca的1B
这三行是一生的痛。。。永远调不出。。。/悲号
for(i=20;i>=0;--i)if(fa[u][i]^fa[v][i])
u=fa[u][i],v=fa[v][i];
return fa[u][0];
AC代码
#include<cmath>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<complex>
#include<iostream>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<string>
#include<bitset>
#include<queue>
#include<set>
#include<map>
using namespace std;
typedef long long ll;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
return x*f;
}
void print(ll x)
{if(x<0)putchar('-'),x=-x;if(x>=10)print(x/10);putchar(x%10+'0');}
const int N=100100;
int n,m,block,qn,cn,bel[N],dfn[N],clr[N];
int ecnt,last[N];
struct EDGE{int to,nt;}e[N<<1];
inline void add(int u,int v)
{e[++ecnt]=(EDGE){v,last[u]};last[u]=ecnt;}
struct question{int u,v,time,id;}q[N];
inline bool cmp(const question &x,const question &y)
{
if(bel[x.u]==bel[y.u]&&bel[x.v]==bel[y.v])return x.time<y.time;
else if(bel[x.u]==bel[y.u])return bel[x.v]<bel[y.v];
return bel[x.u]<bel[y.u];
}
struct change_color{int x,y,pre;}chg[N];
int prvn;
int cnt,size[N],d[N],fa[N][21],s[N],top;
void getblock(int u)
{
register int i;
dfn[u]=++cnt;s[++top]=u;
for(i=last[u];i;i=e[i].nt)
{
if(e[i].to==fa[u][0])continue;
fa[e[i].to][0]=u;d[e[i].to]=d[u]+1;getblock(e[i].to);
size[u]+=size[e[i].to];
if(size[u]>=block)
{
size[u]=0;++prvn;
while(s[top]^u)bel[s[top--]]=prvn;
}
}
size[u]++;
}
void fill(int u,int tp)
{
bel[u]?tp=bel[u]:bel[u]=tp;register int i;
for(i=last[u];i;i=e[i].nt)if(e[i].to^fa[u][0])fill(e[i].to,tp);
}
void init()
{register int i,j;for(j=1;j<=20;++j)for(i=1;i<=n;++i)fa[i][j]=fa[fa[i][j-1]][j-1];}
inline int getlca(int u,int v)
{
if(d[u]<d[v])swap(u,v);
register int len=d[u]-d[v],i;
for(i=0;(1<<i)<=len;++i)if((1<<i)&len)u=fa[u][i];
if(u==v)return u;
for(i=20;i>=0;--i)if(fa[u][i]^fa[v][i])
u=fa[u][i],v=fa[v][i];
return fa[u][0];
}
ll res,W[N],V[N];
bool vis[N];
int num[N];
inline void cal(int u)
{vis[u]?res-=W[num[clr[u]]--]*V[clr[u]]:res+=W[++num[clr[u]]]*V[clr[u]];vis[u]^=1;}
void work(int u,int v)
{while(u^v){if(d[u]<d[v])swap(u,v);cal(u);u=fa[u][0];}}
void modify(int x,int y)
{if(vis[x]){cal(x);clr[x]=y;cal(x);}clr[x]=y;}
ll ans[N];
void solve()
{
register int i,j,lca;
for(i=1;i<=q[1].time;++i)modify(chg[i].x,chg[i].y);
lca=getlca(q[1].u,q[1].v);work(q[1].u,q[1].v);cal(lca);ans[q[1].id]=res;cal(lca);
for(i=2;i<=qn;++i)
{
for(j=q[i-1].time+1;j<=q[i].time;++j)modify(chg[j].x,chg[j].y);
for(j=q[i-1].time;j>q[i].time;--j)modify(chg[j].x,chg[j].pre);
work(q[i-1].u,q[i].u);
work(q[i-1].v,q[i].v);
lca=getlca(q[i].u,q[i].v);
cal(lca);ans[q[i].id]=res;cal(lca);
}
}
int pre_clr[N];
int main()
{
n=read();m=read();
register int i,opt,u,v,Q=read();
for(i=1;i<=m;++i)V[i]=read();
for(i=1;i<=n;++i)W[i]=read();
block=pow(n,2.0/3)*0.5;
for(i=1;i<n;++i){u=read();v=read();add(u,v);add(v,u);}
for(i=1;i<=n;++i)pre_clr[i]=clr[i]=read();
getblock(1);fill(1,prvn);init();
for(i=1;i<=Q;++i)
{
opt=read();u=read();v=read();
if(opt){if(dfn[u]>dfn[v])swap(u,v);q[++qn].time=cn;q[qn].u=u;q[qn].v=v;q[qn].id=qn;}
else{chg[++cn].x=u;chg[cn].y=v;chg[cn].pre=pre_clr[u];pre_clr[u]=v;}
}
sort(q+1,q+1+qn,cmp);
solve();
for(i=1;i<=qn;++i)print(ans[i]),puts("");
return 0;
}
/*
4 3 5
1 9 2
7 6 5 1
2 3
3 1
3 4
1 2 3 2
1 1 2
1 4 2
0 2 1
1 1 2
1 4 2
84
131
27
84
*/