zoukankan      html  css  js  c++  java
  • 【刷题】洛谷 P1501 [国家集训队]Tree II

    题目描述

    一棵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的余数。

    输入输出格式

    输入格式:

    第一行两个整数n,q

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

    接下来q行,每行描述一个操作

    输出格式:

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

    输入输出样例

    输入样例#1:

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

    输出样例#1:

    4

    说明

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

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

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

    100%的数据保证,1<=n,q<=105,0<=c<=104

    By (伍一鸣)

    题解

    这个题类似模板,只是变成了维护加法和乘法
    类似于维护线段数时的加法和乘法
    维护乘法时,要乘维护的和,点的权值和加法的lazy标记
    维护加法的话,就直接加就行了
    (这道题我有个地方少打了个=号,结果找了一个半小时。。)

    #include<bits/stdc++.h>
    #define ll long long
    #define db double
    #define ld long double
    #define lc(x) ch[(x)][0]
    #define rc(x) ch[(x)][1]
    const int MAXN=100000+10,Mod=51061;
    ll n,q,Val[MAXN];
    struct LCT{
    	ll ch[MAXN][2],fa[MAXN],rev[MAXN],size[MAXN],sum[MAXN],add[MAXN],mul[MAXN];
    	inline void init()
    	{
    		for(register int i=1;i<=n;++i)Val[i]=size[i]=sum[i]=mul[i]=1;
    		memset(ch,0,sizeof(ch));
    		memset(fa,0,sizeof(fa));
    		memset(rev,0,sizeof(rev));
    	}
    	inline bool nroot(ll x)
    	{
    		return rc(fa[x])==x||lc(fa[x])==x;
    	}
    	inline void reverse(ll x)
    	{
    		std::swap(lc(x),rc(x));
    		rev[x]^=1;
    	}
    	inline void plus(ll x,ll k)
    	{
    		(Val[x]+=k)%=Mod;
    		(sum[x]+=size[x]*k%Mod)%Mod;
    		(add[x]+=k)%=Mod;
    	}
    	inline void multi(ll x,ll k)
    	{
    		(Val[x]*=k)%=Mod;
    		(sum[x]*=k)%=Mod;
    		(add[x]*=k)%=Mod;(mul[x]*=k)%=Mod;
    	}
    	inline void pushup(ll x)
    	{
    		size[x]=size[lc(x)]+size[rc(x)]+1;
    		sum[x]=(sum[lc(x)]+sum[rc(x)]+Val[x])%Mod;
    	}
    	inline void pushdown(ll x)
    	{
    		if(mul[x]!=1)
    		{
    			multi(lc(x),mul[x]);multi(rc(x),mul[x]);
    			mul[x]=1;
    		}
    		if(add[x])
    		{
    			plus(lc(x),add[x]);plus(rc(x),add[x]);
    			add[x]=0;
    		}
    		if(rev[x])
    		{
    			if(lc(x))reverse(lc(x));
    			if(rc(x))reverse(rc(x));
    			rev[x]=0;
    		}
    	}
    	inline void rotate(ll x)
    	{
    		ll f=fa[x],p=fa[f],c=(rc(f)==x);
    		if(nroot(f))ch[p][rc(p)==f]=x;
    		fa[ch[f][c]=ch[x][c^1]]=f;
    		fa[ch[x][c^1]=f]=x;
    		fa[x]=p;
    		pushup(f);
    		pushup(x);
    	}
    	inline void splay(ll x)
    	{
    		std::stack<ll> s;
    		s.push(x);
    		for(register int i=x;nroot(i);i=fa[i])s.push(fa[i]);
    		while(!s.empty())pushdown(s.top()),s.pop();
    		for(register int y=fa[x];nroot(x);rotate(x),y=fa[x])
    			if(nroot(y))rotate((lc(y)==x)==(lc(fa[y])==y)?y:x);
    		pushup(x);
    	}
    	inline void access(ll x)
    	{
    		for(register ll y=0;x;x=fa[y=x])splay(x),rc(x)=y,pushup(x);
    	}
    	inline void makeroot(ll x)
    	{
    		access(x);splay(x);reverse(x);
    	}
    	inline void split(ll x,ll y)
    	{
    		makeroot(x);access(y);splay(y);
    	}
    	inline void link(ll x,ll y)
    	{
    		makeroot(x);fa[x]=y;
    	}
    	inline void cut(ll x,ll y)
    	{
    		split(x,y);fa[x]=lc(y)=0;pushup(y);
    	}
    };
    LCT T;
    template<typename T> inline void read(T &x)
    {
    	T data=0,w=1;
    	char ch=0;
    	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
    	if(ch=='-')w=-1,ch=getchar();
    	while(ch>='0'&&ch<='9')data=((T)data<<3)+((T)data<<1)+(ch^'0'),ch=getchar();
    	x=data*w;
    }
    template<typename T> inline void write(T x,char c='')
    {
    	if(x<0)putchar('-'),x=-x;
    	if(x>9)write(x/10);
    	putchar(x%10+'0');
    	if(c!='')putchar(c);
    }
    template<typename T> inline void chkmin(T &x,T y){x=(y<x?y:x);}
    template<typename T> inline void chkmax(T &x,T y){x=(y>x?y:x);}
    template<typename T> inline T min(T x,T y){return x<y?x:y;}
    template<typename T> inline T max(T x,T y){return x>y?x:y;}
    int main()
    {
    	read(n);read(q);
    	T.init();
    	for(register int i=1;i<n;++i)
    	{
    		ll u,v;
    		read(u);read(v);
    		T.link(u,v);
    	}
    	while(q--)
    	{
    		char opt;
    		std::cin>>opt;
    		if(opt=='+')
    		{
    			ll u,v,c;
    			read(u);read(v);read(c);
    			T.split(u,v);T.plus(v,c);
    		}
    		if(opt=='*')
    		{
    			ll u,v,c;
    			read(u);read(v);read(c);
    			T.split(u,v);T.multi(v,c);
    		}
    		if(opt=='/')
    		{
    			ll u,v;
    			read(u);read(v);
    			T.split(u,v);
    			write(T.sum[v],'
    ');
    		}
    		if(opt=='-')
    		{
    			ll u1,v1,u2,v2;
    			read(u1);read(v1);read(u2);read(v2);
    			T.cut(u1,v1);T.link(u2,v2);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    linux系统调用是通过软中断实现的吗
    Linux系统调用怎么和内核或底层驱动交互的
    strace命令
    linux 用户态和内核态以及进程上下文、中断上下文 内核空间用户空间理解
    C语言string.h常用函数总结
    shall的过去式和should怎么区分
    P(Y|X) 和 P(X,Y)
    Sourceinsight最佳配色方案及颜色字体调整方法
    float 为什么可以表示很大的整数
    协方差矩阵
  • 原文地址:https://www.cnblogs.com/hongyj/p/8688060.html
Copyright © 2011-2022 走看看