您的位置:首页 > 其它

【BZOJ 3052】 [wc2013]糖果公园

2015-01-28 20:39 253 查看

3052: [wc2013]糖果公园

Time Limit: 250 Sec Memory Limit: 512 MB

Submit: 481 Solved: 176

[Submit][Status]

Description



Input



Output



Sample Input



Sample Input

Sample Output

84

131

27

84

HINT





带修改的树上莫队。

完成
【BZOJ 3757】(不带修改的树上莫队)之后,这道题就好理解了。

与bzoj3757一样,先对树分块,把询问以块和查询时间为关键字排序,关键就是转移了。

(curV,curU)到(targetV,targetU)的转移与bzoj3757一致,那么修改怎么处理呢?

预处理出每一个询问操作的前一个修改操作是第几个。

分两种情况:

1.输入中cur比target靠前,那么我们只要把从cur后面到target之间的所有修改处理一次就可以。

2.输入中cur比target靠后,那么我们需要预处理出每一个修改操作中修改之前的颜色是pre,把cur到target之间的修改处

理一次,与上面不同的是现在要把当前颜色修改成pre。

综上,只要在(curV,curU)到(targetV,targetU)转移之前对时间进行上述转移即可。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#define M 100005
#define LL long long
using namespace std;
LL v[M],w[M],Ans[M],ans=0LL;
int k,QQ1,dfs_clock=0,dep[M],dfn[M],be[M],b[25],f[M][22],h[M],tot=0,cnt=0,Q,QQ,n,m,vi[M],s[M],top=0,c[M],num[M],pre[M];
struct edge
{
int y,ne;
}e[M*2];
struct Q1
{
int x,y,k,pre;
}q1[M],qq[M];
struct Query
{
int x,y,id,t;
}q[M];
void r(int &tmp)
{
tmp=0;
char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar());
for (;ch>='0'&&ch<='9';ch=getchar())
tmp=(tmp*10)+ch-'0';
}
void R(LL &tmp)
{
tmp=0LL;
char ch=getchar();
for (;ch<'0'||ch>'9';ch=getchar());
for (;ch>='0'&&ch<='9';ch=getchar())
tmp=(tmp*10)+ch-'0';
}
void Addedge(int x,int y)
{
e[++tot].y=y;
e[tot].ne=h[x];
h[x]=tot;
}
void dfs(int x)
{
dfn[x]=++dfs_clock;
int bottom=top;
for (int i=h[x];i;i=e[i].ne)
{
int y=e[i].y;
if (f[x][0]==y) continue;
f[y][0]=x;
dep[y]=dep[x]+1;
dfs(y);
if (top-bottom>=k)
{
cnt++;
while (top!=bottom)
be[s[top--]]=cnt;
}
}
s[++top]=x;
}
void prepare()
{
b[0]=1;
for (int i=1;i<=16;i++)
b[i]=b[i-1]<<1;
for (int j=1;j<=16;j++)
for (int i=1;i<=n;i++)
f[i][j]=f[f[i][j-1]][j-1];
}
bool cmp(Query a,Query b)
{
if (be[a.x]==be[b.x])
{
if (be[a.y]==be[b.y])
return a.t<b.t;
return be[a.y]<be[b.y];
}
return be[a.x]<be[b.x];
}
void Calc(int x)
{
if (vi[x])
ans=ans-(v[c[x]]*(w[num[c[x]]--]));
else
ans=ans+(v[c[x]]*(w[++num[c[x]]]));
vi[x]^=1;
}
void Modifytime(int x,int y)
{
if (q[x].id<q[y].id)
{
for (int i=q[x].id+1;i<=q[y].id;i++)
{
int now=c[qq[i].x],mo=qq[i].y;
if (vi[qq[i].x])
{
Calc(qq[i].x);
c[qq[i].x]=mo;
Calc(qq[i].x);
}
else c[qq[i].x]=mo;
}
return;
}
for (int i=q[x].id;i>q[y].id;i--)
{
int now=c[qq[i].x],mo=qq[i].pre;
if (vi[qq[i].x])
{
Calc(qq[i].x);
c[qq[i].x]=mo;
Calc(qq[i].x);
}
else c[qq[i].x]=mo;
}
}
void Move(int &x,int deep)
{
for (int i=16;i>=0;i--)
if (dep[f[x][i]]>=deep)
x=f[x][i];
}
int Getlca(int x,int y)
{
if (dep[x]>dep[y]) swap(x,y);
Move(y,dep[x]);
if (x==y) return x;
for (int i=16;i>=0;i--)
if (f[x][i]!=f[y][i])
x=f[x][i],y=f[y][i];
return f[x][0];
}
void Solve(int x,int y)
{
while (x!=y)
{
if (dep[x]<dep[y])  swap(x,y);
Calc(x);
x=f[x][0];
}
}
int main()
{
r(n),r(m),r(QQ);
k=sqrt(n);
for (int i=1;i<=m;i++)
R(v[i]);
for (int i=1;i<=n;i++)
R(w[i]);
for (int i=1;i<n;i++)
{
int x,y;
r(x),r(y);
Addedge(x,y),Addedge(y,x);
}
dep[1]=1;
dfs(1);
while (top)
be[s[top--]]=cnt;
prepare();
for (int i=1;i<=n;i++)
r(c[i]),pre[i]=c[i];
for (int i=1;i<=QQ;i++)
{
int t,x,y;
r(t),r(x),r(y);
if (!t)
{
QQ1++;
qq[QQ1].x=x,qq[QQ1].y=y;
qq[QQ1].pre=pre[x];
pre[x]=y;
}
else
{
Q++;
if (dfn[x]>dfn[y])
swap(x,y);
q[Q].x=x,q[Q].y=y;
q[Q].id=QQ1;
q[Q].t=Q;
}
}
sort(q+1,q+1+Q,cmp);
ans=0LL;
q[0].id=0,q[0].x=q[0].y=1;
for (int i=1;i<=Q;i++)
{
Modifytime(i-1,i);
Solve(q[i-1].x,q[i].x);
Solve(q[i-1].y,q[i].y);
int a=Getlca(q[i].x,q[i].y);
Calc(a);
Ans[q[i].t]=ans;
Calc(a);
}
for (int i=1;i<=Q;i++)
printf("%lld\n",Ans[i]);
return 0;
}


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: