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,跑的挺快的。


  • 相关阅读:
    Control.CheckForIllegalCrossThreadCalls
    c#禁止Webbrowser控件的弹出脚本错误对话框
    c#,WebBrowser 判断网页是否加载完毕
    c#里的动态数组ArrayList
    C#数据类型转换
    Net2.0 的新线程 ParameterizedThreadStart &BackgroundW
    在C#中使用委托的方式触发事件
    ASP.NET运行原理
    第六讲:ObjC 内存管理4 自动释放池
    第二讲:ObjC 点语法
  • 原文地址:https://www.cnblogs.com/Vanisher/p/9136044.html
Copyright © 2011-2022 走看看