首页 > 代码库 > BZOJ 3786 星系探索 DFS序+Splay
BZOJ 3786 星系探索 DFS序+Splay
题目大意:给定一棵有根树,提供下列操作:
1.询问某个点到根路径上的点权和
2.修改某个点的父亲,保证修改之后仍然是一棵树
3.将某个点所在子树的所有点权加上一个值
子树修改,LCT明显是搞不了了,在想究竟会不会有人去写自适应Top-Tree……
首先我们DFS搞出这棵树的入栈出栈序 然后入栈为正出栈为负
那么一个点到根的路径上的点权和就是从根节点的入栈位置到这个点的入栈位置的和
子树修改就记录某段序列中有多少入栈和多少出栈,然后根据这个对这棵子树所在序列修改即可
那么换父亲操作呢?显然可以用Splay来维护入栈出栈序 将某棵子树所在序列整体移动即可
题还没出来我这题解已经写完了 又强又厉害啊
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 100100 using namespace std; typedef long long ll; struct abcd{ abcd *ls,*rs,*fa; ll num,sum; int sta,pos,neg; ll add_mark; abcd (ll x,int _sta); void Push_Up(); void Push_Down(); void Add(ll x); }*null=new abcd(0,0),*root,*tree[M][2]; struct edge{ int to,next; }table[M]; int head[M],tot; int n,m; int a[M]; abcd :: abcd(ll x,int _sta) { ls=rs=fa=null; num=sum=x*(_sta==1?1:-1); sta=_sta; pos=neg=0; if(sta==1) pos++; if(sta==2) neg++; add_mark=0; } void abcd :: Push_Up() { sum=ls->sum+rs->sum+num; pos=ls->pos+rs->pos+(sta==1); neg=ls->neg+rs->neg+(sta==2); } void abcd :: Push_Down() { if(add_mark) { ls->Add(add_mark); rs->Add(add_mark); add_mark=0; } } void abcd :: Add(ll x) { if(this==null) return ; num+=x*(sta==1?1:-1); sum+=x*(pos-neg); add_mark+=x; } void Push_Down(abcd *x) { static abcd *stack[M<<1]; static int top=0; for(;x!=null;x=x->fa) stack[++top]=x; while(top) stack[top--]->Push_Down(); } 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->fa->ls==y) y->fa->ls=x; else y->fa->rs=x; y->fa=x; y->Push_Up(); if(root==y) root=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->fa->ls==y) y->fa->ls=x; else y->fa->rs=x; y->fa=x; y->Push_Up(); if(root==y) root=x; } void Splay(abcd *x,abcd *tar) { Push_Down(x); while(1) { abcd *y=x->fa,*z=y->fa; if(y==tar) break; if(z==tar) { if(x==y->ls) Zig(x); else Zag(x); break; } if(x==y->ls) { if(y==z->ls) Zig(y); Zig(x); } else { if(y==z->rs) Zag(y); Zag(x); } } x->Push_Up(); } abcd* Insert(ll x,int _sta) { abcd *y=root; while(y->rs!=null) y=y->rs; y->rs=new abcd(x,_sta); y->rs->fa=y; y->Push_Up(); Splay(y->rs,null); return root; } abcd* Find_Min(abcd *x) { while(x->ls!=null) x=x->ls; return x; } abcd* Find_Max(abcd *x) { while(x->rs!=null) x=x->rs; return x; } void Move_To_Root(abcd *x,abcd *y) { Splay(x,null); abcd *temp1=Find_Max(root->ls); Splay(y,null); abcd *temp2=Find_Min(root->rs); Splay(temp1,null); Splay(temp2,root); } void Add(int x,int y) { table[++tot].to=y; table[tot].next=head[x]; head[x]=tot; } void DFS(int x) { int i; tree[x][0]=Insert(a[x],1); for(i=head[x];i;i=table[i].next) DFS(table[i].to); tree[x][1]=Insert(a[x],2); } int main() { int i,x,y; char p[10]; cin>>n; for(i=2;i<=n;i++) scanf("%d",&x),Add(x,i); for(i=1;i<=n;i++) scanf("%d",&a[i]); root=new abcd(19980402,3); DFS(1); Insert(19980402,4); cin>>m; for(i=1;i<=m;i++) { scanf("%s",p); switch(p[0]) { case 'Q': scanf("%d",&x); Move_To_Root(tree[1][0],tree[x][0]); printf("%lld\n",root->rs->ls->sum); break; case 'C': { scanf("%d%d",&x,&y); Move_To_Root(tree[x][0],tree[x][1]); abcd *temp=root->rs->ls; root->rs->ls=null; root->rs->Push_Up(); root->Push_Up(); Splay(tree[y][0],null); Splay(Find_Min(root->rs),root); root->rs->ls=temp; temp->fa=root->rs; root->rs->Push_Up(); root->Push_Up(); break; } case 'F': scanf("%d%d",&x,&y); Move_To_Root(tree[x][0],tree[x][1]); root->rs->ls->Add(y); break; } } }
BZOJ 3786 星系探索 DFS序+Splay
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。