[2016北京集训试题14]股神小D-[LCT]

Description

Solution

将(u,v,l,r)换为(1,u,v,l)和(2,u,v,r)。进行排序(第4个数为第一关键字,第1个数为第二关键字)。用LCT维护联通块的合并和断开。(维护联通块的大小,要维护虚边)

答案统计:每当四元组的第一个数为1(这时候合并点u,v所在连通块,反之拆开),在合并前ans+=size[u]*size[v]即可。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=2e5+10;
long long ans;
struct LCT
{
    int val[N],sz[N],v[N],fa[N],ch[N][2],rev[N];
    bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
    bool get(int x){return ch[fa[x]][1]==x;}
    void updata(int x){sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+v[x]+1;}
    void rotate(int x)
    {
        int k=get(x),y=fa[x];
        ch[y][k]=ch[x][k^1];fa[ch[y][k]]=y;
        if (!isroot(y)) ch[fa[y]][ch[fa[y]][1]==y]=x;fa[x]=fa[y];
        fa[y]=x;ch[x][k^1]=y;
        updata(y);
        updata(x);
    }
    void pushdown(int x)
    {
        if (rev[x])
        {
            swap(ch[x][0],ch[x][1]);
            rev[ch[x][0]]^=1;rev[ch[x][1]]^=1;
            rev[x]=0;
        }
    }
    int q[N],cnt;
    void splay(int x)
    {
        int y;
        q[cnt=1]=x;
        for (int i=x;!isroot(i);i=fa[i]) q[++cnt]=fa[i];
        for (int i=cnt;i>=1;i--) pushdown(q[i]),fa[q[i]]=fa[q[i]];
        while (!isroot(x))
        {
            y=fa[x];
            if (!isroot(y)) rotate(get(x)==get(y)?y:x);
            rotate(x);
        }
    }
    void access(int x)
    {
        int y=0;
        while (x)
        {
            splay(x);
            v[x]+=sz[ch[x][1]]-sz[y];
            ch[x][1]=y;
            updata(x);
            y=x;x=fa[x];
        }
    }
    void mroot(int x)
    {
        access(x);splay(x);rev[x]^=1;
    }
    void link(int x,int y)
    {
        mroot(x);access(y);splay(y);
        ans+=1ll*sz[x]*sz[y];
        fa[x]=y;v[y]+=sz[x];updata(y);
    }
    void cut(int x,int y)
    {
        mroot(x);access(y);splay(y);
        fa[x]=ch[y][0]=0;
        updata(y);
    }
}lct;
int n,u,v,l,r;
struct Q{int t,u,v,w;
    friend bool operator <(Q a,Q b){return a.w==b.w?a.t<b.t:a.w<b.w;}
}q[N<<1];
int main()
{
    scanf("%d",&n);
    for (int i=1;i<n;i++)
    {
        scanf("%d%d%d%d",&u,&v,&l,&r);
        q[i*2-1]=Q{1,u,v,l};q[i*2]=Q{2,u,v,r};
    }
    sort(q+1,q+2*n-1);
    for (int i=1;i<=2*n-2;i++)
    {
        if (q[i].t==1) lct.link(q[i].u,q[i].v);
        else lct.cut(q[i].u,q[i].v);
    }
    cout<<ans;
}

原文地址:https://www.cnblogs.com/coco-night/p/9696166.html

时间: 2024-08-25 23:07:05

[2016北京集训试题14]股神小D-[LCT]的相关文章

[2016北京集训试题6]网络战争-[最小割树(网络流)+kd-tree+倍增]

Description A 联邦国有 N 个州,每个州内部都有一个网络系统,有若干条网络线路,连接各个 州内部的城市. 由于 A 国的州与州之间的关系不是太好,每个州都只有首府建立了到别的州的网络.具体来说,每个州的首府都只主动地建立了一条网络线路,连接到距离最近的州的 首府.(欧氏距离.如果有多个,选择标号最小的去连接) B 国探知了 A 国的网络线路分布情况,以及攻陷每条网络线路所需花费的代价,B 国首脑想知道断开 A 国某两个城市之间的网络连接,所需的最少代价.请你计算出来告 诉他. 注:

[2016北京集训试题15]项链-[FFT]

Description Solution 设y[i+k]=y[i]+n. 由于我们要最优解,则假如将x[i]和y[σ[i]]连线的话,线是一定不会交叉的. 所以,$ans=\sum (x_{i}-y_{i+s}+c)^{2}$ 拆开得$ans=\sum (x_{i}^{2}+y_{i+s}^{2}+c^{2}-2x_{i}y_{i+s}+2x_{i}c-2y_{i+s}c)$ 其中,$x_{i}y_{i+s}$是卷积形式. 我们把经过处理的y数组reverse一下,和x数组进行卷积(这里用ntt

[XSY 1556] 股神小D LCT维护子树信息

实现 1 2 #include <cstdio> 3 #include <cstring> 4 #include <cstdlib> 5 #include <cctype> 6 #include <algorithm> 7 #include <vector> 8 using namespace std; 9 #define F(i, a, b) for (register int i = (a); i <= (b); i++)

股神小L 2016Vijos省选集训 day1

股神小L (stock.c/pas/cpp)============================ 小L厌倦了算法竞赛,希望到股市里一展身手.他凭借自己还行的计算机功底和可以的智商,成功建立一个模型预测了一支股票接下来n天的价格. 我们把这支股票第i天的价格称为a_i.在接下来n天里,每一天小L可以选择花费a_i买入一股或者卖出一股从而获得a_i元收入. 当然小L卖出股票的时候,自己的账户上必须要有至少一股的剩余.现在小L希望知道,在n天过去之后,采取最优策略的情况下自己最多赚到多少钱. 注意

【2016北京集训测试赛(八)】 crash的数列

Description 题解 题目说这是一个具有神奇特性的数列!这句话是非常有用的因为我们发现,如果套着这个数列的定义再从原数列引出一个新数列,它居然还是一样的...... 于是我们就想到了能不能用多点数列套着来加速转移呢? 但是发现好像太多数列套起来是可以烦死人的...... 我们就采用嵌套两次吧,记原数列为A,第一层嵌套为B,第二层嵌套为C. 我们其实可以发现一些规律,对于Ci,它对应了B中i的个数:对于Bi,它对应了A中i的个数. 稍加处理即可,我们一边计算一边模拟数列的运算,同时可以计算

百度在线考试编程题:股神小赛

小赛买股票了,本金为1元,第1天过后不变还是1元,从第二天开始涨1天跌1天,涨2天跌1天,涨3天跌1天,涨4天跌1天,……每次涨幅或跌幅都是1元,求第n天他还有多少钱(大致描述了下题目,具体我也不知道了) 自己比较笨的方法做的,相对高手来说代码量比较大(水平太low,大家见谅).代码如下: 1 /*********计算股价*********/ 2 /*********根据规律,将天数分成段数,计算股价和*********/ 3 #include <stdio.h> 4 #define Base

【2016北京集训测试赛】azelso(unfinished)

[吐槽] 首先当然是要orzyww啦 以及orzyxq奇妙顺推很强qwq 嗯..怎么说呢虽然说之前零零散散做了一些概d的题目但是总感觉好像并没有弄得比较明白啊..(我的妈果然蒟蒻) 这题的话可以说是难得的一道搞得比较清楚的概d题目吧记录一下还是挺有意思的ovo 当然咯..显然考场上并没有推出来..嗯qwq [题解] 看到说要求期望的距离,然后总的长度又被分成了一段一段的(各个事件) 所以就有一个比较直接的想法:将每一段期望走的次数算出来然后再乘上每一段的距离,加起来就是答案啦 那么现在问题来了怎

【2016北京集训测试赛(八)】直径

注意:时限更改为4s 题解 考虑最原始的直径求法:找到离根节点(或离其他任意一点)最远的节点far1,再从far1出发找到离far1最远的节点far2,far1至far2的距离即为直径. 题目中提到了将原树的子树复制成新子树这一操作,显然如果我们将子树真正复制出来是会爆炸的. 实际上我们可以将每棵新子树中,真正有用的节点提取出来,以简化每个子树的结构,再按照题目的要求连接各个新子树. 我们用虚树来重构每一棵子树.每棵子树的虚树的关键点应至少包含: 子树的根节点. 这棵子树内部的直径的两端节点.

【2016北京集训测试赛(七)】自动机 (思考题)

Time Limit: 1000 ms Memory Limit: 256 MB Description Solution 这是一道看起来令人毫无头绪的题,然而确实十分简单巧妙TAT. 题目要求所有点执行相同指令后都回到初始状态. 我们先来考虑只有两种状态的情况:初始状态$T_0$与另一个状态$T_x$. 这样,我们可以通过一个二元记忆化深搜,来得到一种方案A,使得$T_0$回到$T_0$,且$T_x$回到$T_0$.如果这个方案都不存在,那么此时无解. 现在我们知道,执行方案A后,$T_x$与