jzoj 5847.【省选模拟2018.8.24】Graph lct+并查集

版权声明:2333 https://blog.csdn.net/liangzihao1/article/details/82021576

Description
小 G 喜欢四处旅游,但是由于城市发展速度太快,小 G 去旅游时经常计划赶不上变化。
小 G 发现自己的旅行计划一共涉及 N 个城市,每个城市初始时有一个欢乐度 W i ,一共有三种影响旅行计划的事件可能发生:
1   a   b 新建一条连接 a , b 两座城市的边。
2   a   b a 城市的欢乐度改为 b
3   a   b 进行一次 a 城市到 b 城市的旅行。
对于每次旅行, 小 G 会将每一条边任意定向,然后从 a 出发经过一些点到达 b ,在这个过程中,小 G 可以经过一个城市多次,小 G 想知道自己经过的所有城市的欢乐度之和的最大值是多少;若 a 城市无法到达 b 城市,输出 1

Input
第一行两个正整数 N , M ,表示城市数和操作数。
接下来一行 N 个非负整数,第 i 个数表示 i 城市的欢乐度 W i
接下来 M 行每行三个正整数 o p , a , b ,表示一次操作。

Output
对于每个 3 操作, 输出一行一个整数, 表示答案。

Sample Input

5 11
94 37 60 30 24
3 5 4
3 4 1
1 1 4
3 1 1
3 5 4
1 2 5
2 1 17
1 4 5
3 2 3
1 2 3
3 3 5

Sample Output

-1
-1
94
-1
-1
121

Data Constraint

对于 15% 的数据, N , M 10
对于 25% 的数据, N , M 100
对于 45% 的数据, N , M 1000
对于 70% 的数据, N , M 10000
对于 100% 的数据, N , M 150000 W i 10000

分析:
如果形成了一个环,那么可以缩成一个点,这个点的权值就是这个连通分量的答案。然后相当于找树上路径最大值,考虑 l c t 维护。
当我们连成一个环时,我们保留一个代表点,维护一个并查集,使原来路径上所有点指向这个点,把他们的权值都给这个点,然后把整棵 s p l a y 的边弄断。然后每次找一个点父亲时,要在并查集上 g e t f a 一下,顺便把这个点的父亲指向 g e t f a 得到的点。

bzoj 2959和这题差不多,但是bzoj上二操作是修改为 b ,jzoj上数据是增加 b ,题意又是改为 b

代码:

#include <iostream>
#include <cmath>
#include <cstdio>

const int maxn=150007;

using namespace std;

int n,m,x,y,op;
int p[maxn],acc[maxn];

struct node{
    int l,r,fa;
    int data,sum;
    int rev;
}t[maxn];

int getfa(int x)
{
    if (!p[x]) return x;
    return (p[x]=getfa(p[x]));
}

void union1(int x,int y)
{
    int u=getfa(x),v=getfa(y);
    if (u==v) return;
    p[v]=u;
}

void updata(int x)
{
    t[x].sum=t[x].data+t[t[x].l].sum+t[t[x].r].sum;
}

bool isroot(int x)
{
    t[x].fa=getfa(t[x].fa);
    return ((t[t[x].fa].l!=x) && (t[t[x].fa].r!=x));
}

void rttr(int x)
{
    int y=t[x].l;
    t[x].l=t[y].r;
    if (t[y].r) t[t[y].r].fa=x;
    t[x].fa=getfa(t[x].fa);
    if (x==t[t[x].fa].l) t[t[x].fa].l=y;
    else if (x==t[t[x].fa].r) t[t[x].fa].r=y;
    t[y].fa=getfa(t[y].fa);
    t[y].fa=t[x].fa;
    t[x].fa=y;
    t[y].r=x;
    updata(x); updata(y);
}

void rttl(int x)
{
    int y=t[x].r;
    t[x].r=t[y].l;
    if (t[y].l) t[t[y].l].fa=x;
    t[x].fa=getfa(t[x].fa);
    if (x==t[t[x].fa].l) t[t[x].fa].l=y;
    else if (x==t[t[x].fa].r) t[t[x].fa].r=y;
    t[y].fa=getfa(t[y].fa);
    t[y].fa=t[x].fa;
    t[x].fa=y;
    t[y].l=x;
    updata(x); updata(y);
}

void remove(int x)
{
    if (!isroot(x)) remove(t[x].fa=getfa(t[x].fa));
    if (t[x].rev)
    {
        t[x].rev^=1;
        swap(t[x].l,t[x].r);
        if (t[x].l) t[t[x].l].rev^=1;
        if (t[x].r) t[t[x].r].rev^=1;
    }
}

void splay(int x)
{
    remove(x);
    while (!isroot(x))
    {
        int p=t[x].fa=getfa(t[x].fa),g=t[p].fa=getfa(t[p].fa);
        if (isroot(p))
        {
            if (x==t[p].l) rttr(p);
                      else rttl(p);
        }
        else
        {
            if (x==t[p].l)
            {
                if (p==t[g].l) rttr(p),rttr(g);
                          else rttr(p),rttl(g);
            }
            else
            {
                if (p==t[g].l) rttl(p),rttr(g);
                          else rttl(p),rttl(g);
            }
        }
    }
}

void access(int x)
{
    int y=0;
    while (x)
    {
        splay(x);
        t[x].r=y;
        updata(x);
        y=x,x=t[x].fa=getfa(t[x].fa);
    }
}

void makeroot(int x)
{
    access(x);
    splay(x);
    t[x].rev^=1;
}

void link(int x,int y)
{
    makeroot(x);
    access(y);
    splay(y);
    t[x].fa=y;
}

void solve(int x,int root)
{
    if (x!=root) t[root].data+=t[x].data;
    union1(root,x);
    if (t[x].l) solve(t[x].l,root);
    if (t[x].r) solve(t[x].r,root);
    t[x].l=0;
    t[x].r=0;
}

int find(int x)
{
    if (!acc[x]) return x;
    return (acc[x]=find(acc[x]));
}

void union2(int x,int y)
{
    int u=find(x),v=find(y);
    if (u==v) return;
    acc[u]=v;
}

int main()
{
    freopen("graph.in","r",stdin);
    freopen("graph.out","w",stdout);
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
    {
        scanf("%d",&t[i].data);
        t[i].sum=t[i].data;
    }           
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&op,&x,&y);  
        if (op==1)
        {
            x=getfa(x); y=getfa(y);         
            if (find(x)!=find(y))
            {
                link(x,y);
                union2(x,y);
            }
            else
            {
                makeroot(x);
                access(y);
                splay(y);
                solve(y,y);
            }
        }
        if (op==2)
        {
            x=getfa(x);
            t[x].data+=y;
            t[x].sum+=y;            
        }
        if (op==3)
        {
            x=getfa(x); y=getfa(y); 
            if (find(x)!=find(y)) printf("-1\n");
            else
            {               
                makeroot(x);
                access(y);
                splay(y);
                printf("%d\n",t[y].sum);
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/liangzihao1/article/details/82021576