原题地址: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
#include
#include
#include
#include
#define LL long long
using namespace std;
const int N=200005;
const int MXN=1000006;
const int P=17;
int n,m,q,col[N],st[N],cnt[N],V[N],W[N],head[N],to[2*N],nxt[2*N],num=0,blo;
int qs=0,md=0;
LL sum[N],ans[N],now=0,vis[2*N];
int dep[N],anc[N][P+3],in[N],out[N],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;i1]][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[N];
struct Modify
{
int pos,pre,nxt;
}M[N];
int getlca(int u,int v)
{
if(dep[u]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.Lelse if(getb(A.R)!=getb(B.R)) return A.Relse return A.tint 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(rg1);
while(lf>Q[i].L) modify(--lf,1);
while(rg>Q[i].R) modify(rg--,-1);
while(lf1);
while(cur1);
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;iint 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;
}