P4842 城市旅行

题目链接

题意分析

首先存在树上的删边连边操作 所以我们使用\(LCT\)维护

然后考虑怎么维护答案

可以发现 对于一条链 我们编号为\(1,2,3,...,n\)

那么期望就是

\[\frac{a_1* 1* n+a_2* 2* (n-1)+a_3* 3* (n-2)+...+a_n* n* 1}{\frac{n*(n+1)}{2}}\]

很显然的 对于当前点\(i\)

穿过\(i\)的区间的左端点有\(i\)

右端点有\(n-i+1\)

乘法原理组合一下就可以了

总共的路径就存在\(\frac{n*(n+1)}{2}\)

分母我们在最后询问的时候直接用求就可以了

关键是我们怎么在\(LCT\)上维护分子

首先对于当前的\(LCT\)

我们考虑一下对于一种情况

a1---a2---a3---a4(根节点)---a5----a6----a7

左边一开始的答案是\(a_1*1*3+a_2*2*2+a_3*3*1\)

然后加入这一条链之后就是\(a_1*1*7+a_2*2*6+a_3*3*5\)

做差之后就是 \(a_1*1*4+a_2*2*4+a_3*3*4\)

也就是\((a_1*1+a_2*2+a_3*3)*(siz_{rc}+1)\)

所以我们维护一个

\[lsum=a_1*1+a_2*2+a_3*3+...+a_n*n\]

那么左边增加的值就是\(lsum_{lc}*(siz_{rc}+1)\)

同理对于右边我们维护
\[rsum=a_1* n+ a_2*(n-1)+a_3*(n-2)+...+a_n*1\]

那么右边增加的值就是\(rsum_{rc}*(siz_{lc}+1)\)

那么

\[val_{rt}=val{lc}+val{rc}+lsum_{lc}* (siz_{rc}+1)+rsum_{rc}* (siz_{lc}+1)+num_{rt}* (siz_{lc}+1)* (siz_{rc}+1)\]

然后我们同样需要维护\(lsum\)以及\(rsum\)

\[lsum=lsum_{lc}+lsum_{rc}+sum_{rc}*(siz_{lc}+1)+num_{rt}*(siz_{lc}+1)\]

\[rsum=rsum_{lc}+rsum_{rc}+sum_{lc}*(siz_{rc}+1)+num_{rt}*(siz_{rc}+1)\]

仔细想一下 式子应该很好理解的

这样的话我们就可以应对\(query()\)的部分了


然后我们需要维护修改的部分

首先 我们思考一下一条链加一个值的影响

首先 单点值以及当前链总和比较好维护

\(lsum\)以及\(rsum\)也就是\(+d*\frac{n* (n+1)}{2}\)

关键是怎么维护分子\(val\)

\[val+=(1*n+2*(n-1)+3*(n-2)+...+n*1)*d\]

然后再捯饬一下

\[1*n+2*(n-1)+3*(n-2)+...+n*1\]

\[=n*(1+2+3+...+n)-(1*2+2*3+...+(n-1)*n)\]

\[=\frac{n*(n+1)}{2}*n-(1^2+2^2+3^2+...+(n-1)^2+1+2+3+...+(n-1))\]

\[\sum_{i=1}^ni^2=\frac{n(n+1)(2n+1)}{6}\]

这样的话我们就可以很好地维护了

同时又要输出最简分数 所以需要求\(gcd\)

CODE:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdlib>
#include<string>
#include<queue>
#include<map>
#include<stack>
#include<list>
#include<set>
#include<deque>
#include<vector>
#include<ctime>
#define ll long long
#define inf 0x7fffffff
#define N 500008
#define IL inline
#define M 308611
#define D double
#define ull unsigned long long
#define R register
using namespace std;
template<typename T>IL void read(T &_)
{
    T __=0,___=1;char ____=getchar();
    while(!isdigit(____)) {if(____=='-') ___=0;____=getchar();}
    while(isdigit(____)) {__=(__<<1)+(__<<3)+____-'0';____=getchar();}
    _=___ ? __:-__;
}
/*-------------OI使我快乐-------------*/
struct LCT
{
    int fa,son[2];
    ll sum,lsum,rsum,val,num,down_tag,siz;
//子树大小其实不用开 long long
//但是由于我自己手写代码的原因 不开long long会WA两个点
    bool tag;
}tre[M];
int n,m,tot,top;
int sta[M];
IL ll gcd(ll x,ll y){return y ? gcd(y,x%y):x;}
IL bool isroot(int x){return !((tre[tre[x].fa].son[0]==x)||(tre[tre[x].fa].son[1]==x));}
IL void pushup(int x)
{
    tre[x].sum=tre[tre[x].son[0]].sum+tre[tre[x].son[1]].sum+tre[x].num;
    tre[x].siz=tre[tre[x].son[0]].siz+tre[tre[x].son[1]].siz+1;
    tre[x].val=tre[tre[x].son[0]].val+tre[tre[x].son[1]].val+tre[tre[x].son[0]].lsum*(tre[tre[x].son[1]].siz+1)+tre[tre[x].son[1]].rsum*(tre[tre[x].son[0]].siz+1)+tre[x].num*(tre[tre[x].son[0]].siz+1)*(tre[tre[x].son[1]].siz+1);
    tre[x].lsum=tre[tre[x].son[0]].lsum+tre[tre[x].son[1]].lsum+tre[tre[x].son[1]].sum*(tre[tre[x].son[0]].siz+1)+tre[x].num*(tre[tre[x].son[0]].siz+1);
    tre[x].rsum=tre[tre[x].son[0]].rsum+tre[tre[x].son[1]].rsum+tre[tre[x].son[0]].sum*(tre[tre[x].son[1]].siz+1)+tre[x].num*(tre[tre[x].son[1]].siz+1);
}
IL void chenge(int y,ll d)
{
    ll cdy=((tre[y].siz+1)*tre[y].siz/2),wzy=(tre[y].siz-1)*tre[y].siz*(tre[y].siz*2-1)/6;
    tre[y].sum+=tre[y].siz*d;
    tre[y].num+=d;
    tre[y].lsum+=cdy*d;
    tre[y].rsum+=cdy*d;
    tre[y].val+=((cdy*tre[y].siz)-(wzy+tre[y].siz*(tre[y].siz-1)/2))*d;
    tre[y].down_tag+=d;
}
IL void rever(int x)
{
    swap(tre[x].son[0],tre[x].son[1]);
//交换子树的话 lsum以及$rsum$也会发生改变
    swap(tre[x].lsum,tre[x].rsum);
    tre[x].tag^=1;
}
IL void down(int x)
{
    if(tre[x].tag)
    {
        if(tre[x].son[0]) rever(tre[x].son[0]);
        if(tre[x].son[1]) rever(tre[x].son[1]);
        tre[x].tag^=1;
    }
    if(tre[x].down_tag)
    {
        chenge(tre[x].son[0],tre[x].down_tag);
        chenge(tre[x].son[1],tre[x].down_tag);
        tre[x].down_tag=0;
    }
}
IL void rotate(int x)
{
    int cdy=tre[x].fa,wzy=tre[tre[x].fa].fa;
    int d=tre[tre[x].fa].son[1]==x;int wson=tre[x].son[d^1];
    if(!isroot(cdy)) tre[wzy].son[tre[wzy].son[1]==cdy]=x;
    tre[x].fa=wzy;tre[cdy].fa=x;tre[x].son[d^1]=cdy;tre[cdy].son[d]=wson;
    if(wson) tre[wson].fa=cdy;pushup(cdy);pushup(x); 
}
IL void Splay(int x)
{
    int cdy=x,wzy=0;top=0;
    sta[++top]=cdy;
    while(!isroot(cdy)) sta[++top]=cdy=tre[cdy].fa;
    while(top>0) down(sta[top--]);
    while(!isroot(x))
    {
//      printf("x x x %d",x);
        cdy=tre[x].fa;wzy=tre[tre[x].fa].fa;
        if(!isroot(cdy))
        {
            if((tre[wzy].son[1]==cdy)^(tre[cdy].son[1]==x)) rotate(x);
            else rotate(cdy);
        }
        rotate(x);
    }
    pushup(x);
}
IL void access(int x)
{
    for(R int now=0;x;x=tre[now=x].fa)
    {
        Splay(x);tre[x].son[1]=now;pushup(x);
    }
}
IL void makeroot(int x)
{
    access(x);Splay(x);rever(x);
}
IL int findroot(int x)
{
    access(x);Splay(x);
    while(tre[x].son[0]) down(x),x=tre[x].son[0];
    return x;
}
IL void split(int x,int y)
{
    makeroot(x);access(y);Splay(y);
}
IL void link(int x,int y)
{
    makeroot(x);
    if(findroot(y)==x) return;
    tre[x].fa=y;
}
IL void cut(int x,int y)
{
    makeroot(x);
    if(findroot(y)==x&&tre[x].fa==y&&tre[x].son[1]==0)
    tre[x].fa=tre[y].son[0]=0;return;
}
IL void add(int x,int y,ll d)
{
    makeroot(x);
    if(findroot(y)==x)
    {
        split(x,y);
        chenge(y,d);
    }
}
int main()
{
//  freopen(".in","r",stdin);
//  freopen("tmp.out","w",stdout);
    read(n);read(m);
    for(R int i=1;i<=n;++i) read(tre[i].num),pushup(i); 
    for(R int i=1,x,y;i<n;++i)
    {
        read(x);read(y);
        link(x,y);
    }
    while(m--)
    {
        int knd,x,y;ll d;
        read(knd);
        if(knd==1)
        {
            read(x);read(y);
            cut(x,y);
        }
        else if(knd==2)
        {
            read(x);read(y);
            link(x,y);
        }
        else if(knd==3)
        {
            read(x);read(y);read(d);
            add(x,y,d);
        }
        else if(knd==4)
        {
            read(x);read(y);
            makeroot(x);
            if(findroot(y)==x) 
            {
                split(x,y);
                ll cdy=tre[y].val,wzy=(tre[y].siz+1)*tre[y].siz/2;ll tmp=gcd(cdy,wzy);
                printf("%lld/%lld\n",cdy/tmp,wzy/tmp);  
            }
            else puts("-1");
        }
    }
//  fclose(stdin);
//  fclose(stdout);
    return 0;
}

HEOI 2019 RP++

猜你喜欢

转载自www.cnblogs.com/LovToLZX/p/10632168.html