BZOJ 3779 重组病毒 LCT+线段树维护DFS序
2015-05-22 17:18
274 查看
题目大意:给定一棵树,初始每个点都有一个颜色,支持三种操作:
1.将某个点到根的路径上所有点染上一种新的颜色
2.将某个点到根的路径上所有点染上一种新的颜色,然后把根设为这个点
3.定义一个点的代价为这个点到根路径上颜色的种类数,求某个点子树中所有点代价的平均值
我真是炖了狗了……
容易发现这玩应就是个LCT,操作1就是Access,操作2就是Move_To_Root,代价就是一个点到根路径上的虚边数量+1
我们用LCT模拟上述操作,用线段树维护DFS序维护信息,一旦LCT中出现了虚实边的切换,就在DFS序上对应的子树+1/-1,查询就直接在线段树上查就行了
说起来容易写起来真是日了狗了
1.将某个点到根的路径上所有点染上一种新的颜色
2.将某个点到根的路径上所有点染上一种新的颜色,然后把根设为这个点
3.定义一个点的代价为这个点到根路径上颜色的种类数,求某个点子树中所有点代价的平均值
我真是炖了狗了……
容易发现这玩应就是个LCT,操作1就是Access,操作2就是Move_To_Root,代价就是一个点到根路径上的虚边数量+1
我们用LCT模拟上述操作,用线段树维护DFS序维护信息,一旦LCT中出现了虚实边的切换,就在DFS序上对应的子树+1/-1,查询就直接在线段树上查就行了
说起来容易写起来真是日了狗了
[code]#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 100100 using namespace std; int n,m; namespace Tree{ struct edge{ int to,next; }table[M<<1]; int head[M],tot; int fa[M][17],dpt[M]; int st[M],ed[M]; void Add(int x,int y) { table[++tot].to=y; table[tot].next=head[x]; head[x]=tot; } int LCA(int x,int y) { int j; if(dpt[x]<dpt[y]) swap(x,y); for(j=16;~j;j--) if(dpt[fa[x][j]]>=dpt[y]) x=fa[x][j]; if(x==y) return x; for(j=16;~j;j--) if(fa[x][j]!=fa[y][j]) x=fa[x][j],y=fa[y][j]; return fa[x][0]; } int Second_LCA(int x,int y) { int j; for(j=16;~j;j--) if(dpt[fa[x][j]]>dpt[y]) x=fa[x][j]; return x; } } namespace DFS_Sequence{ struct Segtree{ Segtree *ls,*rs; long long sum,mark; void* operator new (size_t) { static Segtree mempool[M<<1],*C=mempool; return C++; } void Add(int x,int y,long long val) { sum+=(y-x+1)*val; mark+=val; } void Push_Up() { sum=ls->sum+rs->sum; } void Push_Down(int x,int y) { int mid=x+y>>1; if(mark) { ls->Add(x,mid,mark); rs->Add(mid+1,y,mark); mark=0; } } void Build_Tree(int x,int y,int a[]) { int mid=x+y>>1; if(x==y) { sum=a[mid]; return ; } (ls=new Segtree)->Build_Tree(x,mid,a); (rs=new Segtree)->Build_Tree(mid+1,y,a); Push_Up(); } void Modify(int x,int y,int l,int r,int val) { int mid=x+y>>1; if(x==l&&y==r) { Add(x,y,val); return ; } Push_Down(x,y); if(r<=mid) ls->Modify(x,mid,l,r,val); else if(l>mid) rs->Modify(mid+1,y,l,r,val); else ls->Modify(x,mid,l,mid,val) , rs->Modify(mid+1,y,mid+1,r,val) ; Push_Up(); } long long Query(int x,int y,int l,int r) { int mid=x+y>>1; if(x==l&&y==r) return sum; Push_Down(x,y); if(r<=mid) return ls->Query(x,mid,l,r); if(l>mid) return rs->Query(mid+1,y,l,r); return ls->Query(x,mid,l,mid) + rs->Query(mid+1,y,mid+1,r) ; } }*_root=new Segtree; int root=1; using namespace Tree; void Build_Tree() { static int a[M]; int i; for(i=1;i<=n;i++) a[st[i]]=dpt[i]; _root->Build_Tree(1,n,a); } void Modify(int x,int val) { if(x==root) { _root->Modify(1,n,1,n,val); return ; } int lca=LCA(x,root); if(lca!=x) _root->Modify(1,n,st[x],ed[x],val); else { lca=Second_LCA(root,x); if(st[lca]!=1) _root->Modify(1,n,1,st[lca]-1,val); if(ed[lca]!=n) _root->Modify(1,n,ed[lca]+1,n,val); } } long long Query_Sum(int x) { if(x==root) return _root->Query(1,n,1,n); long long re=0; int lca=LCA(x,root); if(lca!=x) re+=_root->Query(1,n,st[x],ed[x]); else { lca=Second_LCA(root,x); if(st[lca]!=1) re+=_root->Query(1,n,1,st[lca]-1); if(ed[lca]!=n) re+=_root->Query(1,n,ed[lca]+1,n); } return re; } int Query_Size(int x) { if(x==root) return n; int re=0; int lca=LCA(x,root); if(lca!=x) re+=ed[x]-st[x]+1; else { lca=Second_LCA(root,x); if(st[lca]!=1) re+=st[lca]-1; if(ed[lca]!=n) re+=n-ed[lca]; } return re; } } namespace Link_Cut_Tree{ struct abcd{ abcd *ls,*rs,*fa; bool rev_mark; abcd(); void _Push_Down(); void Push_Down(); void Reverse(); }*null=new abcd,tree[M]; abcd :: abcd() { ls=rs=fa=null; rev_mark=false; } void abcd :: _Push_Down() { if(rev_mark) { ls->Reverse(); rs->Reverse(); rev_mark=false; } } void abcd :: Push_Down() { if(fa->ls==this||fa->rs==this) fa->Push_Down(); _Push_Down(); } void abcd :: Reverse() { swap(ls,rs); rev_mark^=1; } void Zig(abcd *x) { abcd *y=x->fa; y->ls=x->rs; x->rs->fa=y; x->rs=y; x->fa=y->fa; if(y==y->fa->ls) y->fa->ls=x; else if(y==y->fa->rs) y->fa->rs=x; y->fa=x; } void Zag(abcd *x) { abcd *y=x->fa; y->rs=x->ls; x->ls->fa=y; x->ls=y; x->fa=y->fa; if(y==y->fa->ls) y->fa->ls=x; else if(y==y->fa->rs) y->fa->rs=x; y->fa=x; } void Splay(abcd *x) { x->Push_Down(); while(x->fa->ls==x||x->fa->rs==x) { abcd *y=x->fa,*z=y->fa; if(x==y->ls) { if(y==z->ls) Zig(y); Zig(x); } else { if(y==z->rs) Zag(y); Zag(x); } } } void Find_Min(abcd *x,int val) { using namespace DFS_Sequence; x->_Push_Down(); while(x->ls!=null) x=x->ls,x->_Push_Down(); Modify(x-tree,val); } void Access(abcd *x) { abcd *y=null; while(x!=null) { Splay(x); if(x->rs!=null) Find_Min(x->rs,1); if(y!=null) Find_Min(y,-1); x->rs=y; y=x;x=x->fa; } } void Move_To_Root(abcd *x) { using namespace DFS_Sequence; Access(x); Splay(x); x->Reverse(); root=x-tree; } } void DFS(int x) { using namespace Tree; using namespace Link_Cut_Tree; static int T; int i; dpt[x]=dpt[fa[x][0]]+1; st[x]=++T; for(i=1;i<=16;i++) fa[x][i]=fa[fa[x][i-1]][i-1]; 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); tree[table[i].to].fa=&tree[x]; } ed[x]=T; } int main() { using namespace Tree; using namespace DFS_Sequence; using namespace Link_Cut_Tree; int i,x,y; char p[10]; cin>>n>>m; for(i=1;i<n;i++) { scanf("%d%d",&x,&y); Add(x,y);Add(y,x); } DFS(1); Build_Tree(); for(i=1;i<=m;i++) { scanf("%s%d",p+1,&x); switch(p[3]) { case 'L': Access(&tree[x]); break; case 'C': Move_To_Root(&tree[x]); break; case 'Q': printf("%.10lf\n",(double)Query_Sum(x)/Query_Size(x)); break; } } return 0; }
相关文章推荐
- bzoj 3779: 重组病毒【LCT+线段树维护dfs序】
- BZOJ 3779 重组病毒 LCT维护子树信息
- bzoj 3779: 重组病毒 LCT+线段树+倍增
- [bzoj] 3779 重组病毒
- bzoj 3779 重组病毒 好题 LCT+dfn序+线段树分类讨论
- BZOJ 3779 重组病毒 ——LCT 线段树
- bzoj千题计划274:bzoj3779: 重组病毒
- BZOJ3779: 重组病毒
- Bzoj3779 重组病毒
- [LCT 线段树 dfs序] BZOJ 3779 重组病毒
- bzoj3779 重组病毒
- 【bzoj 3779】重组病毒
- BZOJ3779 重组病毒
- bzoj3779 重组病毒 [lct+树链剖分]
- 【bzoj3779】重组病毒 LCT+树上倍增+DFS序+树状数组区间修改区间查询
- bzoj3779-重组病毒
- bzoj 3779: 重组病毒
- 【BZOJ3779】重组病毒 LCT+DFS序
- 【BZOJ】3779 重组病毒
- bzoj3779: 重组病毒