hdu 4010 (LCT模板)

来源:互联网 发布:mac桌面没了咋办v 编辑:程序博客网 时间:2024/04/28 21:29

树的节点权值修改,边的分割,边的链接,某两点之间路径上的最大节点权值。

典型的LCT模板题!

我的代码比较冗长,是用以前做别的题的模板修改得来的,所以有些函数没有用到,不过也很有参考价值(遇到别的类似的题,可以直接修改就ok了~),是个很好的模板!

代码如下:

/*一颗树,有很多操作:(1)加上边a-b;(2)将树以a为根,然后删除b和它的父节点的边;(3)a->b的路径上的所有点权加上d(包含a,b);(4)查询a->b的路径上最大的点权;不合法的操作输出-1.*/#include <stdio.h>#include <string.h>#include <iostream>#include <algorithm>#include <vector>#include <queue>#include <set>#include <map>#include <string>#include <math.h>#include <stdlib.h>#include <time.h>using namespace std;const int INF = 0x3f3f3f3f;const int MAXN = 300110;struct Node *null;struct Node{Node *fa,*ch[2];int val,size;  //val是该点的权重,size是以它为根的子树的大小。int same,add;int rev;int mm,mmc;int sm,smc;inline void clear(int _val){  //初始化该点的点权。fa = ch[0] = ch[1] = null;val = _val; size = 1;same = -INF;add = 0;mm = _val; mmc = 1;sm = -INF; smc = 0;}inline void add_val(int _val,int num){  //权值为val,出现的次数为numif(_val == -INF)return;if(_val < sm)return;if(_val == sm)smc += num;else if(_val < mm){sm = _val; smc = num;}else if(_val == mm){mmc += num;}else{sm = mm; smc = mmc;mm = _val; mmc = num;}}inline void push_up(){size = 1 + ch[0]->size + ch[1]->size;mm = sm = -INF;mmc = smc = 0;add_val(val,1);add_val(ch[0]->mm,ch[0]->mmc);add_val(ch[0]->sm,ch[0]->smc);add_val(ch[1]->mm,ch[1]->mmc);add_val(ch[1]->sm,ch[1]->smc);}inline void setc(Node *p,int d){ch[d] = p;p->fa = this;}inline bool d(){return fa->ch[1] == this;}inline bool isroot(){return fa == null || fa->ch[0] != this && fa->ch[1] != this;}inline void flip(){if(this == null)return;swap(ch[0],ch[1]);rev ^= 1;}inline void update_add(int w){if(this == null)return;if(mm != -INF)mm += w;if(sm != -INF)sm += w;val += w;add += w;}inline void update_same(int w){if(this == null)return;mm = w; mmc = size;sm = -INF; smc = 0;same = w;val = w;add = 0;}inline void push_down(){if(same != -INF){ch[0]->update_same(same);ch[1]->update_same(same);same = -INF;}if(add){ch[0]->update_add(add);ch[1]->update_add(add);add = 0;}if(rev){ch[0]->flip();ch[1]->flip();rev = 0;}}inline void go(){if(!isroot())fa->go();push_down();}inline void rot(){Node *f = fa, *ff = fa->fa;int c = d(), cc = fa->d();f->setc(ch[!c],c);this->setc(f,!c);if(ff->ch[cc] == f)ff->setc(this,cc);else this->fa = ff;f->push_up();}inline Node* splay(){go();while(!isroot()){if(!fa->isroot())d()==fa->d() ? fa->rot() : rot();rot();}push_up();return this;}inline Node* access(){for(Node *p = this,*q = null; p != null; q = p, p = p->fa){p->splay()->setc(q,1);p->push_up();}return splay();}inline Node* find_root(){Node *x;for(x = access(); x->push_down(), x->ch[0] != null; x = x->ch[0]);return x;}void make_root(){access()->flip();}void cut(){access();ch[0]->fa = null;ch[0] = null;push_up();}void cut(Node *x){    //删除该节点和x之间的边。if(this == x || find_root() != x->find_root()) {printf("-1\n");return;}else{x->make_root();cut();}}void link(Node *x){    //该节点链接x节点。(即该节点和x节点之间加一条边)if(find_root() == x->find_root()) {printf("-1\n");return;}else {make_root(); fa = x;}}};void SAME(Node *x,Node *y,int w){    //(2)a->b的路径上的所有点权改为x(包含a,b);x->access();for(x = null; y != null; x = y, y = y->fa){y->splay();if(y->fa == null){y->ch[1]->update_same(w);x->update_same(w);y->val = w;y->push_up();return;}y->setc(x,1);y->push_up();}}void ADD(Node *x,Node *y,int w){  //(3)a->b的路径上的所有点权加上d(包含a,b);x->access();for(x = null; y != null; x = y, y = y->fa){y->splay();if(y->fa == null){y->ch[1]->update_add(w);x->update_add(w);y->val += w;y->push_up();return;}y->setc(x,1);y->push_up();}}int MM,MMC;  //最大值,最大值出现的次数int SM,SMC;  //第二大值,及出现的次数void ADD_VAL(int val,int num){    //权值为val,出现的次数是numif(val == -INF)return;if(val < SM)return;if(val == SM)SMC += num;else if(val < MM){SM = val;SMC = num;}else if(val == MM){MMC += num;}else {SM = MM; SMC = MMC;MM = val; MMC = num;}}void ask(Node *x,Node *y){    //查询a->b的路径上严格第二大的值,以及它出现的次数;x->access();for(x=null; y != null; x = y, y = y->fa){y->splay();if(y->fa == null){MM = SM = -INF;MMC = SMC = 0;ADD_VAL(y->val,1);ADD_VAL(y->ch[1]->mm,y->ch[1]->mmc);ADD_VAL(y->ch[1]->sm,y->ch[1]->smc);ADD_VAL(x->sm,x->smc);ADD_VAL(x->mm,x->mmc);return;}y->setc(x,1);y->push_up();}}Node pool[MAXN],*tail;Node *node[MAXN];//用来加快建树,防止题目卡时间。struct Edge{int to,next;}edge[MAXN*2];int head[MAXN],tot;void init(){tot = 0;memset(head,-1,sizeof(head));}inline void addedge(int u,int v){edge[tot].to = v;edge[tot].next = head[u];head[u] = tot++;}int g[MAXN];int fa[MAXN];void bfs(int s){  //用来建树int l,r;g[l=r=1] = s;fa[s] = s;while(l <= r){int u = g[l++];for(int i = head[u];i != -1;i = edge[i].next){int v = edge[i].to;if(v == fa[u])continue;fa[v] = u;node[v]->fa = node[u];g[++r] = v;}}}int main(){    //freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);int n,m;//scanf("%d",&T);while(scanf("%d",&n)!=EOF){tail = pool;null = tail++;null->fa = null->ch[0] = null->ch[1] = null;null->size = null->rev = 0;null->same = -INF; null->add = 0;null->mm = null->sm = -INF;null->mmc = null->smc = 0;init();int u,v;for(int i = 1;i < n;i++){scanf("%d%d",&u,&v);addedge(u,v);  //这里本来可以直接用node[u]->link(node[v]);来直接建边的,但是会慢一点。addedge(v,u);}for(int i = 1;i <= n;i++){int v ;scanf("%d",&v);  //初始化点权node[i] = tail++;node[i]->clear(v);}bfs(1);  //一定要先初始化点权以后再建树!scanf("%d",&m);int op;int x,y,a,b;while(m--){scanf("%d",&op);if(op == 1){scanf("%d%d",&a,&b);node[a]->link(node[b]);  //a-b建边}else if(op == 2){scanf("%d%d",&a,&b);if(a==b||node[a]->find_root()!=node[b]->find_root())                {                    printf("-1\n");                }                else {                    node[a]->make_root();  //变为以a为根    node[b]->cut(node[b]->fa);  //删掉b和它的父节点的边                }            }else if(op == 3){scanf("%d%d%d",&x,&a,&b);if(node[a]->find_root()!=node[b]->find_root())                {                    printf("-1\n");                }                else                {                    ADD(node[a],node[b],x);//(2)a->b的路径上的所有点权加上x(包含a,b);                }}else{scanf("%d%d",&a,&b);if(node[a]->find_root()!=node[b]->find_root())                {                    printf("-1\n");                }                else                {                    ask(node[a],node[b]);                     printf("%d\n",MM);                }}}printf("\n");}    return 0;}


 

0 0