您的位置:首页 > 其它

uoj #58. 【WC2013】糖果公园(树上莫队算法+修改操作)

2016-04-02 11:15 483 查看
【题目链接】

http://uoj.ac/problem/58

【题意】

有一棵树,结点有自己的颜色,若干询问:u,v路径上的获益,并提供修改颜色的操作。

其中获益定义为Vc*W1+Vc*W2+…+Vc*Wcnt,cnt为经过颜色c的次数。

【思路】

如果没有修改操作就和 苹果树 这道题一样了。

加上修改操作,我们可以对每一个修改操作打上一个时间戳,并记录每一个查询最后修改的时间戳。这样在莫队“区间移动”的时候,只需要根据时间戳进行时光逆流或顺流,即加上现在时间内前一个时间没有的修改或消除现在时间内没有前一个时间存在的修改。

对于一个修改,如果已经打上标记即这时候计入了now,我们应该先把它在路径上取反存在性,修改后再取反一下就又以新的权值回到了路上,就是重新计算一下贡献。

【代码】

#include<set>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define trav(u,i) for(int i=front[u];i;i=e[i].nxt)
#define FOR(a,b,c) for(int a=(b);a<=(c);a++)
using namespace std;

typedef long long ll;
const int N = 3e5+10;
const int D = 21;

ll read() {
char c=getchar();
ll f=1,x=0;
while(!isdigit(c)) {
if(c=='-') f=-1; c=getchar();
}
while(isdigit(c))
x=x*10+c-'0',c=getchar();
return x*f;
}

struct Edge { int v,nxt;
}e[N<<2];
int en=1,front
;
void adde(int u,int v)
{
e[++en]=(Edge){v,front[u]}; front[u]=en;
}

int n,m,B,Q,dfsc,top,Bcnt;
int cnt
,C
; ll now,ans
,W
,V
;
int pos
,dfn
,dep
,fa
[D],vis
,st
,pre
;

struct Node
{
int id,u,v,t;
bool operator < (const Node& rhs) const
{
if(pos[u]==pos[rhs.u]&&pos[v]==pos[rhs.v]) return t<rhs.t;
else if(pos[u]==pos[rhs.u]) return pos[v]<pos[rhs.v];
else return pos[u]<pos[rhs.u];
}
} q
;
struct opNode { int u,v,pre;
} que
;

int qs,cs;

int dfs(int u)
{
FOR(i,1,D-1)
fa[u][i]=fa[fa[u][i-1]][i-1];
dfn[u]=++dfsc;
int siz=0;
trav(u,i) {
int v=e[i].v;
if(v!=fa[u][0]) {
fa[v][0]=u;
dep[v]=dep[u]+1;
siz+=dfs(v);
if(siz>=B) {
Bcnt++;
while(siz--)
pos[st[top--]]=Bcnt;
}
}
}
st[++top]=u;
return siz+1;
}
int lca(int u,int v)
{
if(dep[u]<dep[v]) swap(u,v);
int t=dep[u]-dep[v];
FOR(i,0,D-1)
if(t&(1<<i)) u=fa[u][i];
if(u==v) return u;
for(int i=D-1;i>=0;i--)
if(fa[u][i]!=fa[v][i])
u=fa[u][i],v=fa[v][i];
return fa[u][0];
}
void Xor(int u)
{
if(vis[u])
vis[u]=0,now-=V[C[u]]*W[cnt[C[u]]--];
else
vis[u]=1,now+=V[C[u]]*W[++cnt[C[u]]];
}
void upd(int u,int v)
{
if(vis[u]) {
Xor(u); C[u]=v; Xor(u);
}
else
C[u]=v;
}
void work(int u,int v)
{
while(u!=v) {
if(dep[u]<dep[v]) swap(u,v);
Xor(u); u=fa[u][0];
}
}

int main()
{
//    freopen("in.in","r",stdin);
//    freopen("out.out","w",stdout);
n=read(),m=read(),Q=read();
B=pow(n,2.0/3)*0.5;
FOR(i,1,m) V[i]=read();
FOR(i,1,n) W[i]=read();
int op,u,v,w;
FOR(i,1,n-1) {
u=read(),v=read();
adde(u,v),adde(v,u);
}
FOR(i,1,n)
pre[i]=C[i]=read();

dfs(1);
++Bcnt;
while(top) pos[st[top--]]=Bcnt;
FOR(i,1,Q)
{
op=read(),u=read(),v=read();
if(op==0) {
++cs;
que[cs].u=u,que[cs].v=v;
que[cs].pre=pre[u]; pre[u]=v;
} else {
++qs;
if(dfn[u]>dfn[v]) swap(u,v);
q[qs].u=u,q[qs].v=v;
q[qs].id=qs; q[qs].t=cs;
}
}
sort(q+1,q+qs+1);
FOR(i,1,q[1].t) upd(que[i].u,que[i].v);
work(q[1].u,q[1].v);
int lc=lca(q[1].u,q[1].v);
Xor(lc);
ans[q[1].id]=now;
Xor(lc);
FOR(i,2,qs)
{
for(int j=q[i-1].t+1;j<=q[i].t;j++) upd(que[j].u,que[j].v);
for(int j=q[i-1].t;j>q[i].t;j--) upd(que[j].u,que[j].pre);
work(q[i-1].u,q[i].u);
work(q[i-1].v,q[i].v);
int lc=lca(q[i].u,q[i].v);
Xor(lc);
ans[q[i].id]=now;
Xor(lc);
}
FOR(i,1,qs) printf("%lld\n",ans[i]);
return 0;
}


P.S.辣鸡错误毁我青春(摔

  说到底还是自己太辣鸡了QAQ
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: