您的位置:首页 > 其它

bzoj3052 [wc2013]糖果公园 (树上带修改莫队)

2017-11-27 21:31 495 查看

bzoj3052 [wc2013]糖果公园

原题地址http://www.lydsy.com/JudgeOnline/problem.php?id=3052

题意:

(权限题贴题面)







Input

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

Output

84

131

27

84

数据范围





题解:

关于树上莫队转序列莫队:

遍历一棵树记录in,out得到一个括号序:

例如:



得到:

1 2 3 3 2 4 10 8 8 5 5 10 4 6 7 7 9 9 6 1

对于两个点u,v的链: (in[u] < in[v])

1.u是v的祖先:从in[u]到in[v],中间出现两次的(in,out)的消掉,剩下的序列。

2.u不是v的祖先:从out[u]到in[v],中间出现两次的(in,out)的消掉,剩下的序列。

这个出现两次消掉就开个数序记录一下。

带修莫队见此

于是这道题就是裸题。

今天卡了一发评测,不仅第一次交没过(还是因为cmp写错TLE),还手滑连续交了两发TLE,还用的是别人的号233。

不远就听见Mercer在那骂:哪个sb交糖果公园还交两发。

以为没被认出来正在那庆幸,就被wys揭发了…

代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#define LL long long
using namespace std;
const int N=200005;
const int MXN=1000006;
const int P=17;
int n,m,q,col
,st
,cnt
,V
,W
,head
,to[2*N],nxt[2*N],num=0,blo;
int qs=0,md=0;
LL sum
,ans
,now=0,vis[2*N];
int dep
,anc
[P+3],in
,out
,seq[2*N],inc=0;
void build(int u,int v)
{
num++;
to[num]=v;
nxt[num]=head[u];
head[u]=num;
}
void dfs(int u,int f)
{
inc++; seq[inc]=u; in[u]=inc;
dep[u]=dep[f]+1;
anc[u][0]=f;
for(int i=1;i<P;i++) anc[u][i]=anc[anc[u][i-1]][i-1];

for(int i=head[u];i;i=nxt[i])
{
int v=to[i];
if(v==f) continue;
dfs(v,u);
}
inc++; seq[inc]=u; out[u]=inc;
}
struct Query
{
int L,R,t,id,pos;
}Q
;
struct Modify
{
int pos,pre,nxt;
}M
;
int getlca(int u,int v)
{
if(dep[u]<dep[v]) swap(u,v);
int d=dep[u]-dep[v];
for(int i=0;d;d>>=1,i++) if(d&1) u=anc[u][i];
if(u==v) return u;
for(int i=P-1;i>=0;i--)
if(anc[u][i]!=anc[v][i]) {u=anc[u][i]; v=anc[v][i]; }
return anc[u][0];
}
int getb(int x) {return (x-1)/blo+1;}
bool cmp(const Query &A,const Query &B)
{
if(getb(A.L)!=getb(B.L)) return A.L<B.L;
else if(getb(A.R)!=getb(B.R)) return A.R<B.R;
else return A.t<B.t;
}
void modify(int pos,int opt)
{
int u=seq[pos];
now-=1LL*sum[cnt[col[u]]]*1LL*V[col[u]];
vis[u]^=1; if(vis[u]) cnt[col[u]]++; else cnt[col[u]]--;

now+=1LL*sum[cnt[col[u]]]*1LL*V[col[u]];
}
void change(int tim,int opt)
{
int pre=M[tim].pre; int nxt=M[tim].nxt; int pos=M[tim].pos;
if(vis[pos])
{
now-=1LL*sum[cnt[col[pos]]]*1LL*V[col[pos]]; cnt[col[pos]]--;
now+=1LL*sum[cnt[col[pos]]]*1LL*V[col[pos]];
col[pos]= opt>0? nxt:pre;
now-=1LL*sum[cnt[col[pos]]]*1LL*V[col[pos]]; cnt[col[pos]]++;
now+=1LL*sum[cnt[col[pos]]]*1LL*V[col[pos]];
}
else col[pos]= opt>0? nxt:pre;
}
void moto()
{
int lf=1,rg=0,cur=0;
for(int i=1;i<=qs;i++)
{
while(rg<Q[i].R) modify(++rg,1);
while(lf>Q[i].L) modify(--lf,1);
while(rg>Q[i].R) modify(rg--,-1);
while(lf<Q[i].L) modify(lf++,-1);
while(cur<Q[i].t) change(++cur,1);
while(cur>Q[i].t) change(cur--,-1);
int lca=Q[i].pos;
ans[Q[i].id]=now;
if(lca)
{
ans[Q[i].id]-=1LL*sum[cnt[col[lca]]]*1LL*V[col[lca]];
ans[Q[i].id]+=1LL*sum[cnt[col[lca]]+1]*1LL*V[col[lca]];
}
}
}
int main()
{
scanf("%d%d%d",&n,&m,&q);
for(int i=1;i<=m;i++) scanf("%d",&V[i]);
for(int i=1;i<=n;i++) scanf("%d",&W[i]);
sum[0]=0; for(int i=1;i<=n;i++) sum[i]=sum[i-1]+1LL*W[i];
for(int i=1;i<n;i++)
{
int u,v; scanf("%d%d",&u,&v);
build(u,v); build(v,u);
}
for(int i=1;i<=n;i++) {scanf("%d",&col[i]); st[i]=col[i];}
dfs(1,1); blo=(int)pow((double)inc,(double)2/3);
for(int i=1;i<=q;i++)
{
int opt,x,y;
scanf("%d%d%d",&opt,&x,&y);
if(opt==0)
{
md++; M[md].pre=col[x]; M[md].pos=x;col[x]=y; M[md].nxt=y;
}
else
{
qs++; Q[qs].id=qs; Q[qs].t=md;
int lca=getlca(x,y);  if(dep[x]>dep[y]) swap(x,y);
if(lca!=x) Q[qs].pos=lca; else Q[qs].pos=0;
if(in[x]>in[y]) swap(x,y);
Q[qs].R=in[y]; Q[qs].L=(out[x]>in[y])? in[x]:out[x];
}
}
for(int i=1;i<=n;i++) col[i]=st[i];
sort(Q+1,Q+qs+1,cmp);
moto();
for(int i=1;i<=qs;i++)
printf("%lld\n",ans[i]);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: