题意:
给出一颗n个结点的树,每个结点上有一种糖果∈[1,m];
一个人经过这个结点品尝糖果j获得的愉悦度为w[time[j]]*val[j] (其中time[j]指j的品尝次数);
给出q次操作,操作有两种:
1:更改某结点的糖果种类;
2:查询某两个结点路径上的愉悦度总和;
题解:
250s的神题,orz各位神犇;
将树分块,每块n^2/3大小,分成n^1/3块;
用莫队算法统计路径上每种糖果的数量;
但是这里有了修改,不能用原来的方式排序了;
所以以左端点所在块为第一关键字,右端点所在块为第二关键字,时间序为第三关键字为所有询问排序;
注意是对询问排序,而修改仍按时间序存储;
然后一一处理询问,每次更改端点之前先把时间调至某次修改之后;
每次调整都是O(1)的,答案就是每个糖果的val乘上w的前缀和了;
这样时间复杂度最坏在O(n^5/3) (LCA的log似乎被忽视了);
我的代码可以跑进100s真是荣幸啊233
代码:
#include<math.h> #include<stdio.h> #include<string.h> #include<algorithm> #define N 110000 using namespace std; typedef long long ll; struct node { int l,r,tim,posl,posr,no; }Q[N]; int to[N<<1],next[N<<1],head[N]; int st[N],belong[N],deep[N],fa[N][20]; int a[N],s[N]; int opx[N],opf[N],opt[N],last[N]; int cnt,tot,bk,top; ll v[N],w[N],ans[N]; ll now; bool vis[N]; bool cmp(node a,node b) { if(a.posl==b.posl) { if(a.posr==b.posr) return a.tim<b.tim; return a.posr<b.posr; } return a.posl<b.posl; } void add(int x,int y) { to[++cnt]=y; next[cnt]=head[x]; head[x]=cnt; } void dfs(int x,int pre,int d) { deep[x]=d; fa[x][0]=pre; int i,y,b=top; for(i=head[x];i;i=next[i]) { if((y=to[i])!=pre) { dfs(y,x,d+1); if(top-b>=bk) { tot++; while(top>b) belong[st[top--]]=tot; } } } st[++top]=x; } int Lca(int x,int y) { while(deep[x]!=deep[y]) { if(deep[x]<deep[y]) swap(x,y); int k=log2(deep[x]-deep[y]); x=fa[x][k]; } if(x==y) return x; int k=log2(deep[x])+1; while(k>=0) { if(fa[x][k]!=fa[y][k]) x=fa[x][k],y=fa[y][k]; k--; } return fa[x][0]; } void update(int x,int op) { now-=w[s[x]]*v[x]; s[x]+=op; now+=w[s[x]]*v[x]; } void change(int t) { if(a[opx[t]]==opf[t]) { a[opx[t]]=opt[t]; if(vis[opx[t]]) { update(opf[t],-1); update(opt[t],1); } } else { a[opx[t]]=opf[t]; if(vis[opx[t]]) { update(opt[t],-1); update(opf[t],1); } } } void slove(int x1,int x2) { int g=Lca(x1,x2); while(x1!=g) { update(a[x1],vis[x1]?-1:1); vis[x1]=!vis[x1]; x1=fa[x1][0]; } while(x2!=g) { update(a[x2],vis[x2]?-1:1); vis[x2]=!vis[x2]; x2=fa[x2][0]; } } int main() { int n,m,q,i,j,k,l,r,x,y,len,op,temp,ti; scanf("%d%d%d",&n,&m,&q); bk=pow(n,2.0/3); for(i=1;i<=m;i++) scanf("%lld",v+i); for(i=1;i<=n;i++) scanf("%lld",w+i),w[i]=w[i-1]+w[i]; for(i=1;i<n;i++) { scanf("%d%d",&x,&y); add(x,y),add(y,x); } for(i=1;i<=n;i++) scanf("%d",a+i),last[i]=a[i]; dfs(1,0,0); while(top) belong[st[top--]]=tot; for(k=1;(1<<k)<=n;k++) for(i=1;i<=n;i++) fa[i][k]=fa[fa[i][k-1]][k-1]; for(i=1,temp=len=0;i<=q;i++) { scanf("%d%d%d",&op,&x,&y); if(op) { temp++; if(belong[x]>belong[y]) swap(x,y); Q[temp].l=x,Q[temp].r=y; Q[temp].posl=belong[x]; Q[temp].posr=belong[y]; Q[temp].tim=len,Q[temp].no=temp; } else { len++; opx[len]=x,opf[len]=last[x],opt[len]=y; last[x]=y; } } q=temp; sort(Q+1,Q+q+1,cmp); l=1,r=1,now=0,ti=0; for(i=1;i<=q;i++) { while(ti<Q[i].tim) change(++ti); while(ti>Q[i].tim) change(ti--); slove(l,Q[i].l); slove(r,Q[i].r); l=Q[i].l,r=Q[i].r; x=Lca(l,r); update(a[x],1); ans[Q[i].no]=now; update(a[x],-1); } for(i=1;i<=q;i++) printf("%lld\n",ans[i]); return 0; }
时间: 2024-10-26 01:52:30