zoukankan      html  css  js  c++  java
  • [bzoj2631]tree【LCT】

    【题目描述】

    Description

     一棵n个点的树,每个点的初始权值为1。对于这棵树有q个操作,每个操作为以下四种操作之一:
    + u v c:将u到v的路径上的点的权值都加上自然数c;
    - u1 v1 u2 v2:将树中原有的边(u1,v1)删除,加入一条新边(u2,v2),保证操作完之后仍然是一棵树;
    * u v c:将u到v的路径上的点的权值都乘上自然数c;
    / u v:询问u到v的路径上的点的权值和,求出答案对于51061的余数。

    Input

      第一行两个整数n,q
    接下来n-1行每行两个正整数u,v,描述这棵树
    接下来q行,每行描述一个操作

    Output

      对于每个/对应的答案输出一行

    Sample Input

    3 2
    1 2
    2 3
    * 1 3 4
    / 1 1

    Sample Output

    4


    HINT

    数据规模和约定

    10%的数据保证,1<=n,q<=2000

    另外15%的数据保证,1<=n,q<=5*10^4,没有-操作,并且初始树为一条链

    另外35%的数据保证,1<=n,q<=5*10^4,没有-操作

    100%的数据保证,1<=n,q<=10^5,0<=c<=10^4


    【题解】

     LCT模板题,讲一下LCT基本操作(对lct一无所知的请看https://www.cnblogs.com/BLADEVIL/p/3510997.html)

    1.access(x):LCT核心操作,将x到root的所有边设为偏爱边,断开其他与这条莲相邻的偏爱边

    2.makeroot(x) :将x变为根

    3.getroad(u,v) :(我YY的)将u设为根并将v转到u所在splay的根上(进行access操作),此时v没有右子树,左子树即要查询的链。

    4.link(u,v):添加u与v的边

    5.cut(u,v):删去u与v的边

    6.isroot(x):判断x是否为当前splay的根,如果是,那么fa[x]的左右儿子都因没有x

    实现见代码:

    /* --------------
        user Vanisher
        problem bzoj-2631 LCT
    ----------------*/
    # include <bits/stdc++.h>
    # define 	ll 		long long
    # define 	ui 		unsigned int
    # define 	N 		100010
    # define 	P 		51061
    using namespace std;
    ui read(){
    	ui tmp=0, fh=1; char ch=getchar();
    	while (ch<'0'||ch>'9'){if (ch=='-') fh=-1; ch=getchar();}
    	while (ch>='0'&&ch<='9'){tmp=tmp*10+ch-'0'; ch=getchar();}
    	return tmp*fh;
    }
    struct lct{
    	ui pl,pr,size,tag,tag0,tag1,sum,num,fa;
    }T[N];
    ui st[N],n,q;
    void pushtag(ui x){
    	if (x==0) return;
    	if (T[x].tag==1){
    		T[T[x].pl].tag^=1; T[T[x].pr].tag^=1; T[x].tag^=1;
    		swap(T[x].pl,T[x].pr);
    	}
    	if (T[x].tag1!=1){
    		ui num=T[x].tag1;
    		T[T[x].pl].tag0=(T[T[x].pl].tag0*num)%P; T[T[x].pl].tag1=(T[T[x].pl].tag1*num)%P;
    		T[T[x].pr].tag0=(T[T[x].pr].tag0*num)%P; T[T[x].pr].tag1=(T[T[x].pr].tag1*num)%P;
    		T[x].num=(T[x].num*T[x].tag1)%P; T[x].sum=(T[x].sum*T[x].tag1)%P;
    		T[x].tag1=1;
    	}
    	if (T[x].tag0!=0){
    		ui num=T[x].tag0;
    		T[T[x].pl].tag0=(T[T[x].pl].tag0+num)%P; T[T[x].pr].tag0=(T[T[x].pr].tag0+num)%P;
    		T[x].sum=(T[x].sum+T[x].tag0*T[x].size)%P; T[x].num=(T[x].num+T[x].tag0)%P;
    		T[x].tag0=0;
    	}
    }
    void change(ui x){
    	pushtag(T[x].pl); pushtag(T[x].pr);
    	T[x].sum=(T[x].num+T[T[x].pl].sum+T[T[x].pr].sum)%P;
    	T[x].size=1+T[T[x].pl].size+T[T[x].pr].size;
    }
    bool isroot(ui x){
    	return T[T[x].fa].pl!=x&&T[T[x].fa].pr!=x;
    }
    void zig(ui x){
    	ui y=T[x].fa;
    	if (!isroot(y)){
    		if (T[T[y].fa].pl==y) T[T[y].fa].pl=x; else T[T[y].fa].pr=x;
    	}
    	T[x].fa=T[y].fa;
    	T[y].pl=T[x].pr; T[T[x].pr].fa=y;
    	T[y].fa=x; T[x].pr=y;
    	change(y); change(x);
    }
    void zag(ui x){
    	ui y=T[x].fa;
    	if (!isroot(y)){
    		if (T[T[y].fa].pl==y) T[T[y].fa].pl=x; else T[T[y].fa].pr=x;
    	}
    	T[x].fa=T[y].fa;
    	T[y].pr=T[x].pl; T[T[x].pl].fa=y;
    	T[y].fa=x; T[x].pl=y;
    	change(y); change(x);
    }
    void splay(ui x){
    	ui y=x,top=0; st[++top]=x;
    	while (!isroot(y)) st[++top]=y=T[y].fa;
    	for (ui i=top; i>=1; i--) pushtag(st[i]);
    	while (!isroot(x)){
    		y=T[x].fa;
    		if (isroot(y))
    			if (T[y].pl==x) zig(x); else zag(x);
    			else if (T[T[y].fa].pl==y)
    				if (T[y].pl==x) zig(y), zig(x);
    					else zag(x), zig(x);
    				else if (T[y].pl==x) zig(x), zag(x);
    					else zag(y), zag(x);
    	}
    }
    void access(ui u){
    	ui v=0;
    	while (u){
    		splay(u);
    		T[u].pr=v; T[v].fa=u;
    		change(u);
    		v=u;
    		u=T[u].fa;
    	}
    }
    void makeroot(ui u){
    	access(u);
    	splay(u);
    	T[u].tag^=1;
    }
    void getroad(ui u, ui v){
    	makeroot(u);
    	access(v);
    	splay(v);
    }
    void link(ui u, ui v){
    	makeroot(u);
    	T[u].fa=v;
    }
    void cut(ui u, ui v){
    	getroad(u,v);
    	T[v].pl=0; T[u].fa=0;
    	change(v);
    }
    int main(){
    	n=read(); q=read();
    	for (ui i=1; i<=n; i++) 
    		T[i].size=1,T[i].tag1=1,T[i].num=T[i].sum=1;
    	for (ui i=1; i<n; i++)
    		link(read(),read());
    	char opt;
    	ui u,v,c;
    	for (ui i=1; i<=q; i++){
    		scanf("
    %c",&opt);
    		if (opt=='+'){
    			u=read(), v=read(); c=read();
    			getroad(u,v);
    		 	T[v].tag0=(T[v].tag0+c)%P;
    		}
    		if (opt=='-'){
    			u=read(), v=read(); cut(u,v);
    			u=read(), v=read(); link(u,v);
    		}
    		if (opt=='*'){
    			u=read(), v=read(); c=read();
    			getroad(u,v);
    		 	T[v].tag1=(T[v].tag1*c)%P;
    		 	T[v].tag0=(T[v].tag0*c)%P;
    		}
    		if (opt=='/'){
    			u=read(), v=read();
    			getroad(u,v);
    			pushtag(v); 
    			printf("%d
    ",T[v].sum);
    		}
    	}
    	return 0;
    }

     tips:此题要用unsigned int,跑的挺快的。


  • 相关阅读:
    新概念第二册(1)--英语口语听力课1
    外企面试课程(一)---熟悉常见的缩略词
    公司 邮件 翻译 培训 长难句 结课
    workflow
    公司 邮件 翻译 培训 长难句 20
    公司 邮件 翻译 培训 长难句 19
    Engineering Management
    公司 邮件 翻译 培训 长难句 18
    公司 邮件 翻译 培训 长难句 17
    第14.5节 利用浏览器获取的http信息构造Python网页访问的http请求头
  • 原文地址:https://www.cnblogs.com/Vanisher/p/9136044.html
Copyright © 2011-2022 走看看