zoukankan      html  css  js  c++  java
  • 【BZOJ3091】城市旅行 LCT

    【BZOJ3091】城市旅行

    Description

    Input

    Output

    Sample Input

    4 5
    1 3 2 5
    1 2
    1 3
    2 4
    4 2 4
    1 2 4
    2 3 4
    3 1 4 1
    4 1 4

    Sample Output

    16/3
    6/1

    HINT

    对于所有数据满足 1<=N<=50,000 1<=M<=50,000 1<=Ai<=10^6 1<=D<=100 1<=U,V<=N

    题解:做过不少在线段树上推式子的,但是头一次做到将式子放到树上然后用splay进行区间合并的~

    $ans=sum v[i]*dep[i]*(dep[y]-dep[i]+1)=sum v[i]*dep[i]*(dep[y]+1)-sum v[i]*dep[i]*dep[i]$

    所以我们只需要维护v[i]*dep[i]和v[i]*dep[i]*dep[i]即可。由于我们在查询时a和b会跑到同一个splay里,所以节点i的dep就是i在splay中的中序遍历序。然后用v[i]更新v[i]*dep[i],用v[i]和v[i]*dep[i]更新v[i]*dep[i]*dep[i]即可。

    但是问题来了,翻转!翻转我们怎么办?翻转操作会使所有的dep全都改变,于是我们需要维护两套v[i],v[i]*dep,v[i]*dep*dep,一套是正的,一套是反的,翻转操作时我们只需要交换这两套即可。

    此外,LCT的瓶颈依然在findroot操作那里,一开始TLE,改了改姿势就过了。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    typedef long long ll;
    const int maxn=50010;
    struct LCT
    {
    	int ch[2],fa,rev;
    	ll v,ts,s0[2],s1[2],s2[2],siz;
    }s[maxn];
    int n,m;
    bool isr(int x)	{return s[s[x].fa].ch[0]!=x&&s[s[x].fa].ch[1]!=x;}
    void add(int x,ll val)
    {
    	s[x].v+=val,s[x].ts+=val;
    	s[x].s0[0]+=s[x].siz*val,s[x].s1[0]+=s[x].siz*(s[x].siz+1)/2*val,s[x].s2[0]+=s[x].siz*(s[x].siz+1)*(2*s[x].siz+1)/6*val;
    	s[x].s0[1]+=s[x].siz*val,s[x].s1[1]+=s[x].siz*(s[x].siz+1)/2*val,s[x].s2[1]+=s[x].siz*(s[x].siz+1)*(2*s[x].siz+1)/6*val;
    }
    void pushup(int x)
    {
    	s[x].siz=s[s[x].ch[0]].siz+s[s[x].ch[1]].siz+1;
    	s[x].s0[0]=s[s[x].ch[0]].s0[0]+s[s[x].ch[1]].s0[0]+s[x].v;
    	s[x].s1[0]=s[s[x].ch[0]].s1[0]+s[s[x].ch[1]].s1[0]+(s[s[x].ch[1]].s0[0]+s[x].v)*(s[s[x].ch[0]].siz+1);
    	s[x].s2[0]=s[s[x].ch[0]].s2[0]+s[s[x].ch[1]].s2[0]+(s[s[x].ch[1]].s0[0]+s[x].v)*(s[s[x].ch[0]].siz+1)*(s[s[x].ch[0]].siz+1)+2*s[s[x].ch[1]].s1[0]*(s[s[x].ch[0]].siz+1);
    	s[x].s0[1]=s[s[x].ch[1]].s0[1]+s[s[x].ch[0]].s0[1]+s[x].v;
    	s[x].s1[1]=s[s[x].ch[1]].s1[1]+s[s[x].ch[0]].s1[1]+(s[s[x].ch[0]].s0[1]+s[x].v)*(s[s[x].ch[1]].siz+1);
    	s[x].s2[1]=s[s[x].ch[1]].s2[1]+s[s[x].ch[0]].s2[1]+(s[s[x].ch[0]].s0[1]+s[x].v)*(s[s[x].ch[1]].siz+1)*(s[s[x].ch[1]].siz+1)+2*s[s[x].ch[0]].s1[1]*(s[s[x].ch[1]].siz+1);
    }
    void rever(int x)
    {
    	s[x].rev^=1;
    	swap(s[x].ch[0],s[x].ch[1]);
    	swap(s[x].s0[0],s[x].s0[1]),swap(s[x].s1[0],s[x].s1[1]),swap(s[x].s2[0],s[x].s2[1]);
    }
    void pushdown(int x)
    {
    	if(s[x].ts)
    	{
    		if(s[x].ch[0])	add(s[x].ch[0],s[x].ts);
    		if(s[x].ch[1])	add(s[x].ch[1],s[x].ts);
    		s[x].ts=0;
    	}
    	if(s[x].rev)
    	{
    		if(s[x].ch[0])	rever(s[x].ch[0]);
    		if(s[x].ch[1])	rever(s[x].ch[1]);
    		s[x].rev=0;
    	}
    }
    void updata(int x)
    {
    	if(!isr(x))	updata(s[x].fa);
    	pushdown(x);
    }
    void rotate(int x)
    {
    	int y=s[x].fa,z=s[y].fa,d=(x==s[y].ch[1]);
    	if(!isr(y))	s[z].ch[y==s[z].ch[1]]=x;
    	s[x].fa=z,s[y].fa=x,s[y].ch[d]=s[x].ch[d^1];
    	if(s[x].ch[d^1])	s[s[x].ch[d^1]].fa=y;
    	s[x].ch[d^1]=y;
    	pushup(y),pushup(x);
    }
    void splay(int x)
    {
    	updata(x);
    	while(!isr(x))
    	{
    		int y=s[x].fa,z=s[y].fa;
    		if(!isr(y))
    		{
    			if((x==s[y].ch[0])^(y==s[z].ch[0]))	rotate(x);
    			else	rotate(y);
    		}
    		rotate(x);
    	}
    }
    void access(int x)
    {
    	for(int y=0;x;splay(x),s[x].ch[1]=y,pushup(x),y=x,x=s[x].fa);
    }
    int findr(int x)
    {
    	while(s[x].fa)	x=s[x].fa;
    	return x;
    }
    void maker(int x)
    {
    	access(x),splay(x),rever(x);
    }
    void link(int x,int y)
    {
    	maker(x),access(y),splay(y),s[x].fa=y;
    }
    void cut(int x,int y)
    {
    	maker(x),access(y),splay(y);
    	if(s[y].ch[0]==x&&!s[x].ch[1])	s[y].ch[0]=s[x].fa=0,pushup(y);
    }
    ll gcd(ll a,ll b)
    {
    	return (!b)?a:gcd(b,a%b);
    }
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    int main()
    {
    	//freopen("bz3091.in","r",stdin);
    	n=rd(),m=rd();
    	int i,a,b,c,d;
    	ll t1,t2,g;
    	for(i=1;i<=n;i++)	s[i].v=rd(),pushup(i);
    	for(i=1;i<n;i++)	a=rd(),b=rd(),link(a,b);
    	for(i=1;i<=m;i++)
    	{
    		d=rd(),a=rd(),b=rd();
    		if(d==1)	cut(a,b);
    		if(d==2)	if(findr(a)!=findr(b))	link(a,b);
    		if(d==3)
    		{
    			c=rd();
    			if(findr(a)==findr(b))	maker(a),access(b),splay(b),add(b,c);
    		}
    		if(d==4)
    		{
    			if(findr(a)!=findr(b))	printf("-1
    ");
    			else
    			{
    				maker(a),access(b),splay(b),t1=(s[b].siz+1)*s[b].s1[0]-s[b].s2[0],t2=s[b].siz*(s[b].siz+1)/2,g=gcd(t1,t2);
    				printf("%lld/%lld
    ",t1/g,t2/g);
    			}
    		}
    	}
    	return 0;
    }
  • 相关阅读:
    C++ map的基本操作和用法
    堆排序汇总
    gdb调试多进程和多线程命令
    Linux内存分配机制
    svn 修改文件的可执行权限
    proc/sys/net/ipv4/下各项的意义
    linux read()和write
    ps命令参数
    /etc/passwd- 和/etc/shadow-文件
    openssh源码分析笔记
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7391543.html
Copyright © 2011-2022 走看看