标签:bzoj bzoj3052 树上莫队 莫队算法 块状树
题目大意:给定一棵树,每个点有一个颜色,提供两种操作:
1.询问两点间路径上的Σv[a[i]]*w[k],其中a[i]代表这个点的颜色,k表示这个点是这种颜色第k次出现
2.修改某个点的颜色
VfleaKing的题解见 http://vfleaking.blog.163.com/blog/static/174807634201311011201627/
带修改莫队上树……如果不带修改就正常搞就好了
如果带修改的话,令块的大小为n^(2/3)
将询问排序时第一键值为左端点所在块,第二键值为右端点所在块,第三键值为询问时间
然后将一个询问跳到下一个的时候先改链上的点,然后处理修改
这样最后可以保证最坏复杂度为O(n^(5/3)) 强行不到O(n^2)……
记住TLE不一定是常数大或者死循环 很可能是莫队写挂了 建议TLE的好好检查一下
另外推荐在半夜刷这道题……不然容易引起民粪……
#include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 100100 using namespace std; namespace IStream{ const int L=1<<15; char buffer[L]; char *S,*T; inline char Get_Char() { if(S==T) { T=(S=buffer)+fread(buffer,1,L,stdin); if(S==T) return EOF; } return *S++; } inline int Get_Int() { int re=0; char c; do c=Get_Char(); while(c<'0'||c>'9'); while(c>='0'&&c<='9') re=(re<<3)+(re<<1)+(c-'0'),c=Get_Char(); return re; } } struct abcd{ int to,next; }table[M<<1]; struct query{ int x,y,pos; bool operator < (const query &Y) const; }queries[M]; struct modification{ int x,from,to,pos; }modifications[M]; int head[M],tot; int n,m,q,B,end;bool flag; int a[M],value[M],incuriosity[M]; int fa[M][20],belong[M],size[M],dpt[M],pos[M]; int cnt[M];bool v[M];long long now,ans[M]; bool query :: operator < (const query &Y) const { if(flag) { if(belong[x]!=belong[Y.x]) return belong[x]<belong[Y.x]; if(belong[y]!=belong[Y.y]) return belong[y]<belong[Y.y]; return pos < Y.pos; } else { if(belong[x]!=belong[Y.x]) return belong[x]<belong[Y.x]; return ::pos[y] < ::pos[Y.y]; } } void Add(int x,int y) { table[++tot].to=y; table[tot].next=head[x]; head[x]=tot; } void DFS(int x) { int i; static int cnt=0,T=0; if(!fa[x][0]||size[belong[fa[x][0]]]==B) size[ belong[x]=++cnt ]++; else size[ belong[x]=belong[fa[x][0]] ]++; dpt[x]=dpt[fa[x][0]]+1;pos[x]=++T; for(i=head[x];i;i=table[i].next) if(table[i].to!=fa[x][0]) fa[table[i].to][0]=x,DFS(table[i].to); } int LCA(int x,int y) { int j; if(dpt[x]<dpt[y]) swap(x,y); for(j=17;j>=0;j--) if(dpt[fa[x][j]]>=dpt[y]) x=fa[x][j]; if(x==y) return x; for(j=17;j>=0;j--) if(fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j]; return fa[x][0]; } void Change(int x) { v[x]^=1; if(v[x]==1) { cnt[a[x]]++; if(cnt[a[x]]>=1) now+=(long long)value[a[x]]*incuriosity[cnt[a[x]]]; } else { if(cnt[a[x]]>=1) now-=(long long)value[a[x]]*incuriosity[cnt[a[x]]]; cnt[a[x]]--; } } void Change(modification temp,bool flag) { if(flag) swap(temp.from,temp.to); a[temp.x]=temp.to; if(v[temp.x]) { if(cnt[temp.from]>=1) now-=(long long)value[temp.from]*incuriosity[cnt[temp.from]]; cnt[temp.from]--; cnt[temp.to]++; if(cnt[temp.to]>=1) now+=(long long)value[temp.to]*incuriosity[cnt[temp.to]]; } } int main() { int i,j,x,y,p,temp,lca; cin>>n>>m>>q; for(i=1;i<=m;i++) value[i]=IStream::Get_Int(); for(i=1;i<=n;i++) incuriosity[i]=IStream::Get_Int(); for(i=1;i<n;i++) { x=IStream::Get_Int(); y=IStream::Get_Int(); Add(x,y); Add(y,x); } for(i=1;i<=n;i++) a[i]=IStream::Get_Int(); temp=0; for(i=1;i<=q;i++) { p=IStream::Get_Int(); x=IStream::Get_Int(); y=IStream::Get_Int(); if(p==1) { if(pos[x]>pos[y]) swap(x,y); queries[++temp].pos=temp; queries[temp].x=x; queries[temp].y=y; } else { flag=1; modifications[++end].x=x; modifications[end].from=a[x]; modifications[end].to=a[x]=y; modifications[end].pos=temp; } } q=temp; if(flag) B=static_cast<int>(pow(n,2.0/3.0)+1e-7); else B=static_cast<int>(sqrt(n)+1e-7); DFS(1); for(j=1;j<=17;j++) for(i=1;i<=n;i++) fa[i][j]=fa[fa[i][j-1]][j-1]; x=y=1;temp=end; sort(queries+1,queries+q+1); for(i=1;i<=q;i++) { lca=LCA(x,queries[i].x); for(j=x;j!=lca;j=fa[j][0]) Change(j); for(j=queries[i].x;j!=lca;j=fa[j][0]) Change(j); lca=LCA(y,queries[i].y); for(j=y;j!=lca;j=fa[j][0]) Change(j); for(j=queries[i].y;j!=lca;j=fa[j][0]) Change(j); lca=LCA(x=queries[i].x,y=queries[i].y); Change(lca); for(;temp>0 && modifications[temp].pos>=queries[i].pos ;temp--) Change(modifications[temp],1); for(;temp<end && modifications[temp+1].pos<queries[i].pos;temp++) Change(modifications[temp+1],0); ans[queries[i].pos]=now; Change(lca); } for(i=1;i<=q;i++) { #ifdef ONLINE_JUDGE printf("%lld\n",ans[i]); #endif #ifdef C_PoPoQQQ printf("%I64d\n",ans[i]); #endif } }
标签:bzoj bzoj3052 树上莫队 莫队算法 块状树
原文地址:http://blog.csdn.net/popoqqq/article/details/41544609