3052: [wc2013]糖果公园
Time Limit: 200 Sec Memory Limit: 512 MBSubmit: 1264 Solved: 637
[ Submit][ Status][ Discuss]
Description
Input
Output
Sample Input
Sample Input
Sample Output
84
131
27
84
131
27
84
HINT
Source
几句闲话
这道题我很快的写完了但是调了超久,而且这道题200s的限时差点被别人喷成卡时狗...这道题如果T了的话要T三分钟多,想象就可怕,幸好我主要是WA,虽然T了一次快被机房的人喷成翔...狗眼观察法怎么都看不出来哪里错了,后来才发现,long long强转的时候后面被强转的东西不能打括号,不然的话就是先计算括号内的东西,爆了int以后再转long long就无济于事了...
题解
一开始怎么都不相信是树上带修改莫队,毕竟n的三分之五次方的时间复杂度几乎就是暴力,这种复杂度只是为了卡掉暴力而已...然而题目的200s允许你这样暴力...一直没写过树上莫队,以及带修改莫队,正好这道题树上带修改莫队,一举两得,赶紧学习一波,一下学两个就当自虐了...
我们可以发现通过括号序列(dfs序的感觉)可以讲两点的简单路径勾勒出来,因为出现两次的在对应括号序列区间我们会把它^掉,就好像()相消一样,一旦异或回0就消除当前点的贡献.将它转化为普通序列之后,就成为一道lca+普通序列带修改莫队了~注意块的大小.
#include<stdio.h>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=200005;
typedef long long dnt;
dnt sum,ans[maxn];
int num,cnt1,cnt2,idc,indexx,n,m,T,block,opt;
int f[maxn],g[maxn],in[maxn],seq[maxn*3],h[maxn],last[maxn],blo[maxn*2],id[maxn*2],cnt[maxn],c[maxn],v[maxn],w[maxn],st[maxn*2][19],vis[maxn];
inline int read(){
register int x=0,f=1;
register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f*=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return f*x;
}
struct query{
int l,r,t,id;
}q[maxn],b[maxn];
inline bool cmp(query x,query y){
return blo[x.l]<blo[y.l]||blo[x.l]==blo[y.l]&&blo[x.r]<blo[y.r]||blo[x.l]==blo[y.l]&&blo[x.r]==blo[y.r]&&x.t<y.t;
}
struct edge{
int v,nxt;
}e[maxn*2];
inline void add(int u,int v){
e[++num].v=v;
e[num].nxt=h[u];
h[u]=num;
}
void dfs(int u,int fa){
f[u]=++idc,id[idc]=u;
seq[++indexx]=u,in[u]=indexx;
for(int i=h[u];i;i=e[i].nxt){
int v=e[i].v;
if(v==fa) continue;
dfs(v,u);
seq[++indexx]=u;
}
g[u]=++idc,id[idc]=u;
}
inline void stha(){
for(register int i=1;i<=indexx;i++) st[i][0]=in[seq[i]];
for(int j=1;(1<<j)<indexx;j++)
for(int i=1;i+(1<<j)-1<=indexx;i++)
st[i][j]=min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
}
inline int query(int L,int R){
if(L>R) swap(L,R);
int len=R-L+1;
int k=0,ans;
while((1<<(k+1))<len) k++;
ans=min(st[L][k],st[R-(1<<k)+1][k]);
return seq[ans];
}
inline void update(int x){
if(vis[x]) sum-=(dnt)v[c[x]]*w[cnt[c[x]]--];
else sum+=(dnt)v[c[x]]*w[++cnt[c[x]]];
vis[x]^=1;
}
inline void chg(int x,int y){
if(vis[x]) update(x),c[x]=y,update(x);
else c[x]=y;
}
int main(){
register int i,l,r,t;
n=read(),m=read(),T=read();
for(i=1;i<=m;i++) v[i]=read();
for(i=1;i<=n;i++) w[i]=read();
for(i=1;i<n;i++) l=read(),r=read(),add(l,r),add(r,l);
for(i=1;i<=n;i++) last[i]=c[i]=read();
dfs(1,1);
stha();
block=(int)pow(n,2.0/3);
for(i=1;i<=idc;i++) blo[i]=(i-1)/block;
for(i=1;i<=T;i++){
opt=read(),l=read(),r=read();
if(opt){
if(f[l]>f[r]) swap(l,r);
q[++cnt1].r=f[r],q[cnt1].t=cnt2,q[cnt1].id=cnt1;
q[cnt1].l=(query(in[l],in[r])==l)?f[l]:g[l];
continue;
}
b[++cnt2].l=l,b[cnt2].t=last[l],last[l]=b[cnt2].r=r;
}
l=1,r=0,t=1,sort(q+1,q+cnt1+1,cmp);
for(i=1;i<=cnt1;i++){
for(;t<=q[i].t;t++) chg(b[t].l,b[t].r);
for(;t>q[i].t;t--) chg(b[t].l,b[t].t);
while(q[i].l<l) update(id[--l]);while(q[i].l>l) update(id[l++]);
while(r>q[i].r) update(id[r--]);while(r<q[i].r) update(id[++r]);
int x=id[l],y=id[r],lca=query(in[x],in[y]);
if(x!=lca&&y!=lca) update(lca),ans[q[i].id]=sum,update(lca);
else ans[q[i].id]=sum;
}
for(i=1;i<=cnt1;i++) printf("%lld\n",ans[i]);
}