本文主要是介绍【codeforces】482E. ELCA 动态树,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
传送门:【codeforces】482E. ELCA
题目大意:给一棵有根树,树根为1,每个节点有权值s[v],q次操作,每次要么将以v为根的子树接到u下,要么令s[v]=t,每次操作以后,输出等概率选择两个点i,j(i可以等于$)后权值的期望,权值即s[{lca(i,j)}]值。
题目分析:写了两天啊啊啊啊!!!终于搞出来了。。。思考这题算法的时候总感觉脑子不够用啊= =于是好不容易AC了一次就再写了一发。。
这题一看就知道是动态树问题,但关键的是怎么转化,比较好的方法是每个节点x保存以这个节点为根结点的子树中LCA为x的路径种数,x的子树大小tree_siz,x在splay中不包括splay树中右儿子tree_siz的siz,这样在处理的过程中改变access函数,每次access一定是将真实树中的树边扩充为splay边,然后很巧妙的就可以转化为路径求和问题。具体只能见代码= =我真的描述不清楚。。。
1.注意cut以及link操作是怎么执行的。
2.注意tree_siz只与真实树有关,所以除了cut及link涉及的修改路径操作,splay的其他操作都对他没有影响。
3.注意siz只在access的时候发生变化。
代码如下:
#include <map>
#include <vector>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std ;typedef long long LL ;#define rep( i , a , b ) for ( int i = ( a ) ; i < ( b ) ; ++ i )
#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )
#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )
#define clr( a , x ) memset ( a , x , sizeof a )const int MAXN = 50005 ;
const int MAXE = 100005 ;struct Node* null ;
struct Node {Node* c[2] ;Node* f ;LL cnt ;LL sum ;int val ;int siz ;int lazy ;int tree_siz ;inline void new_node () {sum = val = 0 ;c[0] = c[1] = f = null ;lazy = 0 ;}inline void add_siz ( int SIZE ) {if ( this == null ) return ;tree_siz += SIZE ;cnt += 2LL * siz * SIZE ;lazy += SIZE ;}inline void push_up () {sum = c[0]->sum + ( LL ) siz * val + c[1]->sum ;}inline void push_down () {if ( lazy ) {c[0]->add_siz ( lazy ) ;c[1]->add_siz ( lazy ) ;lazy = 0 ;}}inline bool is_root () {return f == null || f->c[0] != this && f->c[1] != this ;}inline void sign_down () {if ( !is_root () ) f->sign_down () ;push_down () ;}inline void setc ( Node* o , bool d ) {c[d] = o ;o->f = this ;}inline void rot ( bool d ) {Node* p = f ;Node* g = f->f ;p->setc ( c[d] , !d ) ;if ( !p->is_root () ) g->setc ( this , p == g->c[1] ) ;else f = g ;setc ( p , d ) ;p->push_up () ;}inline void splay () {sign_down () ;while ( !is_root () ) {if ( f->is_root () ) rot ( this == f->c[0] ) ;else {if ( f == f->f->c[0] ) {if ( this == f->c[0] ) f->rot ( 1 ) , rot ( 1 ) ;else rot ( 0 ) , rot ( 1 ) ;} else {if ( this == f->c[1] ) f->rot ( 0 ) , rot ( 0 ) ;else rot ( 1 ) , rot ( 0 ) ;}}}push_up () ;}inline void access () {Node* o = this ;Node* x = null ;while ( o != null ) {if ( x != null ) {while ( x->c[0] != null ) x = x->c[0] ;x->splay () ;}o->splay () ;o->siz = o->tree_siz - x->tree_siz ;//without splay_tree right_son tree_sizo->setc ( x , 1 ) ;o->push_up () ;x = o ;o = o->f ;}splay () ;}
} ;struct Edge {int v ;Edge* next ;
} ;Node pool[MAXN] ;
Node* node[MAXN] ;
Node* curN ;
Edge edge[MAXE] ;
Edge* H[MAXN] ;
Edge* curE ;
LL ans ;
int n , m ;void clear () {ans = 0 ;curE = edge ;curN = pool ;null = curN ++ ;null->new_node () ;null->cnt = null->tree_siz = null->siz = 0 ;clr ( H , 0 ) ;
}void addedge ( int u , int v ) {curE->v = v ;curE->next = H[u] ;H[u] = curE ++ ;
}void dfs ( int u ) {node[u]->cnt = node[u]->tree_siz = 1 ;for ( Edge* e = H[u] ; e ; e = e->next ) {int v = e->v ;dfs ( v ) ;node[u]->cnt += 2LL * node[u]->tree_siz * node[v]->tree_siz ;node[u]->tree_siz += node[v]->tree_siz ;}ans += node[u]->cnt * node[u]->val ;//calculate init ansnode[u]->siz = node[u]->tree_siz ;
}void solve () {int x , y ;char op[2] ;double tot = ( double ) n * n ;clear () ;For ( i , 1 , n ) {node[i] = curN ++ ;node[i]->new_node () ;}For ( i , 2 , n ) {scanf ( "%d" , &x ) ;addedge ( x , i ) ;node[i]->f = node[x] ;}For ( i , 1 , n ) scanf ( "%d" , &node[i]->val ) ;dfs ( 1 ) ;printf ( "%.10f\n" , ans / tot ) ;scanf ( "%d" , &m ) ;while ( m -- ) {scanf ( "%s%d%d" , op , &x , &y ) ;if ( op[0] == 'P' ) {node[y]->access () ;node[x]->splay () ;if ( node[x]->f == null ) swap ( x , y ) ;//cutnode[x]->access () ;Node* o = node[x]->c[0] ;ans -= 2LL * o->sum * node[x]->tree_siz ;o->add_siz ( -node[x]->tree_siz ) ;node[x]->c[0]->f = null ;node[x]->c[0] = null ;node[x]->push_up () ;o->push_up () ;//linknode[y]->access () ;ans += 2LL * node[y]->sum * node[x]->tree_siz ;node[y]->add_siz ( node[x]->tree_siz ) ;node[y]->push_up () ;node[x]->f = node[y] ;} else {node[x]->access () ;ans += node[x]->cnt * ( y - node[x]->val ) ;node[x]->val = y ;node[x]->push_up () ;}printf ( "%.10f\n" , ans / tot ) ;}
}int main () {while ( ~scanf ( "%d" , &n ) ) solve () ;return 0 ;
}
压缩后代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define clr(a,x) memset(a,x,sizeof a)
const int MAXN=50005;
const int MAXE=100005;
struct Node *null;
struct Node{Node *c[2],*f;LL cnt,sum;int val,siz,lazy,tree_siz;inline void new_node(){sum=val=lazy=0,c[0]=c[1]=f=null;}inline void add_siz(int SIZE){if(this==null)return;tree_siz+=SIZE;cnt+=2LL*siz*SIZE;lazy+=SIZE;}inline void up(){sum=c[0]->sum+(LL)siz*val+c[1]->sum;}inline void down(){if(lazy)c[0]->add_siz(lazy),c[1]->add_siz(lazy),lazy=0;}inline bool is_root(){return f==null||f->c[0]!=this&&f->c[1]!=this;}inline void sign_down(){if(!is_root())f->sign_down();down();}inline void setc(Node *o,bool d){c[d]=o,o->f=this;}inline void rot(bool d){Node *p=f,*g=f->f;p->setc(c[d],!d);if(!p->is_root())g->setc(this,p==g->c[1]);else f=g;setc(p,d);p->up();}inline void splay(){for(sign_down();!is_root();){if(f->is_root())rot(this==f->c[0]);else{if(f==f->f->c[0])this==f->c[0]?f->rot(1):rot(0),rot(1);else this==f->c[1]?f->rot(0):rot(1),rot(0);}}up();}inline void access(){for(Node*o=this,*x=null;o!=null;x=o,o=o->f){if(x!=null){while(x->c[0]!=null)x=x->c[0];x->splay();}o->splay();o->siz=o->tree_siz-x->tree_siz;//withoutsplay_treeright_sontree_sizo->setc(x,1);o->up();}splay();}
}pool[MAXN],*node[MAXN],*curN;;
struct Edge{int v;Edge *next;
}edge[MAXE],*H[MAXN],*curE;
LL ans;
int n,m;
void init(){ans=0;curE=edge;curN=pool;null=curN++;null->new_node();null->cnt=null->tree_siz=null->siz=0;clr(H,0);
}
void addedge(int u,int v){curE->v=v;curE->next=H[u];H[u]=curE++;
}
void dfs(int u){node[u]->cnt=node[u]->tree_siz=1;for(Edge *e=H[u];e;e=e->next){int v=e->v;dfs(v);node[u]->cnt+=2LL*node[u]->tree_siz*node[v]->tree_siz;node[u]->tree_siz+=node[v]->tree_siz;}ans+=node[u]->cnt*node[u]->val;//calculateinitansnode[u]->siz=node[u]->tree_siz;
}
void solve(){int x,y,i;char op[2];double tot=(double)n*n;init();for(i=1;i<=n;++i){node[i]=curN++;node[i]->new_node();}for(i=2;i<=n;++i){scanf("%d",&x);addedge(x,i);node[i]->f=node[x];}for(i=1;i<=n;++i)scanf("%d",&node[i]->val);dfs(1);printf("%.10f\n",ans/tot);scanf("%d",&m);while(m--){scanf("%s%d%d",op,&x,&y);if(op[0]=='P'){node[y]->access();node[x]->splay();if(node[x]->f==null)swap(x,y);//cutnode[x]->access();Node *o=node[x]->c[0];ans-=2LL*o->sum*node[x]->tree_siz;o->add_siz(-node[x]->tree_siz);node[x]->c[0]->f=null;node[x]->c[0]=null;node[x]->up();o->up();//linknode[y]->access();ans+=2LL*node[y]->sum*node[x]->tree_siz;node[y]->add_siz(node[x]->tree_siz);node[y]->up();node[x]->f=node[y];}else{node[x]->access();ans+=node[x]->cnt*(y-node[x]->val);node[x]->val=y;node[x]->up();}printf("%.10f\n",ans/tot);}
}
int main(){while(~scanf("%d",&n))solve();return 0;
}
这篇关于【codeforces】482E. ELCA 动态树的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!