BZOJ 2631 Tree Link-Cut-Tree(LCT)

题目大意:维护一棵树,提供四种操作:

1.将x到y的路径上所有的点权值+z

2.将x1到y1的边断开,然后将x2和y2链接,数据保证链接后仍然是棵树

3.将x到y的路径上所有的点权值*z

4.询问x到y路径上节点的权值和对51061取模

我就复制粘贴算了为何要重新打一遍委屈

Link-Cut-Tree第一道功能比较全的题,比较水,水个*啊,很久以前就写完了,由于BZ挂了一直没交上去,今天交上去之后从中午开始TLE,一直TLE到现在。。。。

史上第一次除了Hash Killer III之外交完50次。。。一次30s,各种酸爽。。。

之前的写法Move_To_Root之后x上还有标记没管,直接把右子树切了,结果标记传不下去,导致死循环。。。血的教训啊啊啊啊!!谁让我不扒标程各种自己敲。。。代码看了不下20遍。。。各种优化常数,读入优化也加了!深搜改广搜!递归全删了!手写系统栈!取模改成减!各种inline!连scanf都被我缩成getchar了!最后切掉之后硬压到10s以内,蛋疼死了。。。。

不想说啥了,想哭。。。。。算了总算切了 切了就好 以后就好写了快哭了

不愧是Link-Cut-Tree,比树链剖分就多出一个Link和一个Cut,难写的也就一个Link和一个Cut。。。

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 100100
#define Mo 51061
using namespace std;
typedef unsigned int u;
inline int getc() {
    static const int L = 1 << 15;
    static char buf[L], *S = buf, *T = buf;
    if (S == T) {
        T = (S = buf) + fread(buf, 1, L, stdin);
        if (S == T)
            return EOF;
    }
    return *S++;
}
inline int getint() {
    int c;
    while(!isdigit(c = getc()) && c != '-');
    bool sign = c == '-';
    int tmp = sign ? 0 : c - '0';
    while(isdigit(c = getc()))
        tmp = (tmp << 1) + (tmp << 3) + c - '0';
    return sign ? -tmp : tmp;
}
inline void output(int x) 
{
	static int a[20];
	if (x == 0)
		putchar('0');
	else {
		int top = 0;
		if (x < 0)
			putchar('-'), x=-x;
		while(x) {
			a[++top] = x % 10;
			x /= 10;
		}
		for(int i = top; i >= 1; --i)
			putchar('0' + a[i]);
	}
	puts("");
}
struct abcd{
    abcd *fa,*ls,*rs;
    int siz;
    u num,sum;
    u add_mark,times_mark;
    bool rev_mark;
    abcd(int x);
    void Push_Down();
    void Push_Up();
    void times(u x);
    void add(u x);
    void rev();
}*null=new abcd(0),*tree[M];
abcd :: abcd(int x)
{
    fa=ls=rs=null;
    if(x) siz=1;
    else siz=0;
    num=sum=x;
    add_mark=0;
    times_mark=1;
}
void abcd :: times(u x)
{
    if(this==null)
        return ;
    times_mark*=x;
    times_mark%=Mo;
    num*=x;
    num%=Mo;
    add_mark*=x;
    add_mark%=Mo;
    sum*=x;
    sum%=Mo;
}
void abcd :: add(u x)
{
    if(this==null)
        return ;
    num+=x;
    num=(num>Mo?num-Mo:num);
    add_mark+=x;
    add_mark=(add_mark>Mo?add_mark-Mo:add_mark);
    sum+=x*siz%Mo;
    sum=(sum>Mo?sum-Mo:sum);
}
void abcd :: rev()
{
	if(this==null)
		return ;
    rev_mark^=1;
    swap(ls,rs);
}
void abcd :: Push_Up()
{
	if(this==null)
		return ;
    sum=(ls->sum+rs->sum+num)%Mo;
    siz=ls->siz+rs->siz+1;
}
void abcd :: Push_Down()
{
    //if(fa->ls==this||fa->rs==this)
    //    fa->Push_Down();
    if(this==null)
    	return ;
    if(times_mark^1)
    {
        ls->times(times_mark);
        rs->times(times_mark);
        times_mark=1;
    }
    if(add_mark)
    {
        ls->add(add_mark);
        rs->add(add_mark);
        add_mark=0;
    }
    if(rev_mark)
    {
        ls->rev();
        rs->rev();
        rev_mark=0;
    }
}
abcd *stack[M];int top;
void Push_Down(abcd *x)
{
	for(;x->fa->ls==x||x->fa->rs==x;x=x->fa)
		stack[++top]=x;
	stack[++top]=x;
	while(top)
		stack[top--]->Push_Down();
}
inline void Zig(abcd *x)
{
	if(x==null)
		return ;
    abcd *y=x->fa;
    y->ls=x->rs;
    x->rs->fa=y;
    x->rs=y;
    x->fa=y->fa;
    if(y==y->fa->ls)
        y->fa->ls=x;
    else if(y==y->fa->rs)
        y->fa->rs=x;
    y->fa=x;
    y->Push_Up();
}
inline void Zag(abcd *x)
{
	if(x==null)
		return ;
    abcd *y=x->fa;
    y->rs=x->ls;
    x->ls->fa=y;
    x->ls=y;
    x->fa=y->fa;
    if(y==y->fa->ls)
        y->fa->ls=x;
    else if(y==y->fa->rs)
        y->fa->rs=x;
    y->fa=x;
    y->Push_Up();
}
inline void Splay(abcd *x)
{
	if(x==null)
		return ;
    Push_Down(x);
    while( x==x->fa->ls||x==x->fa->rs )
    {
        abcd *y=x->fa,*z=y->fa;
        if( z->ls!=y&&z->rs!=y )
        {
			if(x==y->ls)
				Zig(x);
			else
				Zag(x);
			break;
		}
        if(z->ls==y)
        {
            if(y->ls==x)
                Zig(y),Zig(x);
            else
                Zag(x),Zig(x);
        }
        else
        {
            if(y->rs==x)
                Zag(y),Zag(x);
            else
                Zig(x),Zag(x);
        }
    }
    x->Push_Up();
}
inline void Access(abcd *x)
{
    abcd *y=null;
    while(x!=null)
    {
        Splay(x);
        x->rs=y;
        x->Push_Up();
        y=x;
        x=x->fa;
    }
}
inline void Move_To_Root(abcd *x)
{
    Access(x);
    Splay(x);
    x->rev();
}
inline void Link(abcd *x,abcd *y)
{
    Move_To_Root(x);
    x->fa=y;
}
inline void Cut(abcd *x,abcd *y)
{
    Move_To_Root(x);
    Access(y);
    Splay(y);
    x->fa=null;
    y->ls=null;
    y->Push_Up();
}
struct ABCD{
    int to,next;
}table[M<<1];
int head[M],tot;
int n,m,fa[M];
inline void add(int x,int y)
{
    table[++tot].to=y;
    table[tot].next=head[x];
    head[x]=tot;
}
int q[M],r,h;
void bfs()
{
    int i;
    q[++r]=1;
    while(r!=h)
    {
    	int x=q[++h];
	    tree[x]=new abcd(1);
	    if(fa[x])
	        tree[x]->fa=tree[ fa[x] ];
	    for(i=head[x];i;i=table[i].next)
	    {
	        if(table[i].to==fa[x])
	            continue;
	        fa[table[i].to]=x;
	        q[++r]=table[i].to;
	    }
    }
}
int main()
{
	
    int i,x,y,z;
    char p;
    n=getint();m=getint();
    for(i=1;i<n;i++)
    {
        x=getint();y=getint();
        add(x,y);
        add(y,x);
    }
    bfs();
    for(i=1;i<=m;i++)
    {
        do{
			p=getc();
		}while(p==' '||p=='\n'||p=='\r');
        if(p=='+')
        {
            x=getint();y=getint();z=getint();
            Move_To_Root(tree[x]);
            Access(tree[y]);
            Splay(tree[y]);
            tree[y]->add(z);
        }
        else if(p=='-')
        {
            x=getint();y=getint();
            Cut(tree[x],tree[y]);
            x=getint();y=getint();
            Link(tree[x],tree[y]);
        }
        else if(p=='*')
        {
            x=getint();y=getint();z=getint();
            Move_To_Root(tree[x]);
            Access(tree[y]);
            Splay(tree[y]);
            tree[y]->times(z);
        }
        else
        {
            x=getint();y=getint();
            Move_To_Root(tree[x]);
            Access(tree[y]);
            Splay(tree[y]);
            output( tree[y]->sum );
        }
    }
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值