zoukankan      html  css  js  c++  java
  • bzoj1180,2843

    1180: [CROATIAN2009]OTOCI

    Time Limit: 50 Sec  Memory Limit: 162 MB
    Submit: 967  Solved: 597
    [Submit][Status][Discuss]

    Description

    给出n个结点以及每个点初始时对应的权值wi。起始时点与点之间没有连边。有3类操作: 1、bridge A B:询问结点A与结点B是否连通。如果是则输出“no”。否则输出“yes”,并且在结点A和结点B之间连一条无向边。 2、penguins A X:将结点A对应的权值wA修改为X。 3、excursion A B:如果结点A和结点B不连通,则输出“impossible”。否则输出结点A到结点B的路径上的点对应的权值的和。给出q个操作,要求在线处理所有操作。数据范围:1<=n<=30000, 1<=q<=300000, 0<=wi<=1000。

    Input

    第一行包含一个整数n(1<=n<=30000),表示节点的数目。第二行包含n个整数,第i个整数表示第i个节点初始时对应的权值。第三行包含一个整数q(1<=n<=300000),表示操作的数目。以下q行,每行包含一个操作,操作的类别见题目描述。任意时刻每个节点对应的权值都是1到1000的整数。

    Output

    输出所有bridge操作和excursion操作对应的输出,每个一行。

    Sample Input

    5
    4 2 4 5 6
    10
    excursion 1 1
    excursion 1 2
    bridge 1 2
    excursion 1 2
    bridge 3 4
    bridge 3 5
    excursion 4 5
    bridge 1 3
    excursion 2 4
    excursion 2 5

    Sample Output

    4
    impossible
    yes
    6
    yes
    yes
    15
    yes
    15
    16

    HINT

    Source

    抄了抄答案,自己想不出来。。。。。。。。

    这道题的重点在于求和,怎么理解很关键。。。

    首先我们一定要记住:splay维护的是一条链,这就很方便了。那么我们想做的就是让这两个点x,y处于一条链中,并且一个在头,一个在尾。那么我们先rever(x),让x到根(似乎LCT的精髓在于把两个点转化到一颗splay中,利用rever和access,把一个点先放到根,在把另外一个点access和根联系起来,因为只有根是他们共同有的,所以利用根进行两个点的联系与连接。)然后再access(y),让y和x联系起来,处于同一颗splay中,然后splay(x,或y),这里只是让一个点到这颗splay的根,从而能获得整个根的和,因为根的和是这条链中所有点的和。很巧妙啊。

    学习东西似乎先抄几遍,然后碰到不会的一边抄一边想,抄完再想一会,似乎效果比想清楚再写好很多,因为第一遍很难想清楚。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define N 3000010
    int n,m;
    int size[N],fa[N],tag[N],st[N],key[N],sum[N];
    int child[N][2];
    void update(int x)
    {
        sum[x]=sum[child[x][0]]+sum[child[x][1]]+key[x];
    }
    void pushdown(int x)
    {
        if(!tag[x]) return;
        tag[x]^=1;
        swap(child[x][0],child[x][1]);
        tag[child[x][0]]^=1;
        tag[child[x][1]]^=1;
    }
    bool isroot(int x)
    {
        return (!fa[x]||(child[fa[x]][0]!=x&&child[fa[x]][1]!=x));
    }
    void zig(int x)
    {
        int y=fa[x];
        fa[x]=fa[y]; 
        if(!isroot(y)) child[fa[x]][child[fa[x]][1]==y]=x;
        child[y][0]=child[x][1]; fa[child[x][1]]=y;
        child[x][1]=y; fa[y]=x;
        update(y); update(x);
    }
    void zag(int x)
    {
        int y=fa[x];
        fa[x]=fa[y]; 
        if(!isroot(y)) child[fa[x]][child[fa[x]][1]==y]=x;
        child[y][1]=child[x][0]; fa[child[x][0]]=y;
        child[x][0]=y; fa[y]=x;
        update(y); update(x);
    }
    void splay(int x)
    {
        int top=0; st[++top]=x;
        for(int y=x;!isroot(y);y=fa[y]) st[++top]=fa[y];
        for(int i=top;i;i--) pushdown(st[i]);
        while(!isroot(x))
        {
            int y=fa[x],z=fa[y];
            if(isroot(y))
            {
                child[y][0]==x?zig(x):zag(x); break;
            }
            child[y][0]==x?zig(x):zag(x);
            child[z][0]==x?zig(x):zag(x);
        }
    }
    void access(int x)
    {
        for(int t=0;x;t=x,x=fa[x]) 
        {
            splay(x);
            child[x][1]=t;
            update(x);
        }
    }
    void rever(int x)
    {
        access(x); splay(x); tag[x]^=1; 
    }
    void link(int x,int y)
    {
        rever(x); fa[x]=y;
        update(x); update(y);
    }
    void cut(int x,int y)
    {
        rever(x); access(y); splay(y); child[y][0]=fa[x]=0;
        update(x); update(y);
    }
    int find(int x)
    {
        access(x); splay(x); 
        for(;child[x][0];x=child[x][0]);
        return x;
    }
    void query1(int x,int y)
    {
        if(find(x)==find(y))
        {
            printf("no
    ");
            return;
        }
        printf("yes
    ");
        link(x,y);
    }
    void change(int x,int y)
    {
        key[x]=y; splay(x);
    }
    void query2(int x,int y)
    {
        if(find(x)!=find(y))
        {
            printf("impossible
    ");
            return;
        }
        rever(x); access(y); splay(x);
        printf("%d
    ",sum[x]);
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) 
        {
            scanf("%d",&key[i]);
            update(i);
        }
        scanf("%d",&m);
        while(m--)
        {
            char s[10]; int x,y; scanf("%s",s);
            if(s[0]=='b')
            {
                scanf("%d%d",&x,&y); query1(x,y);
            }
            if(s[0]=='p')
            {
                scanf("%d%d",&x,&y); change(x,y);
            }
            if(s[0]=='e')
            {
                scanf("%d%d",&x,&y); query2(x,y);
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    解决帝国CMS搜索页面模板不支持灵动标签和万能标签的方法
    Visual Studio Code 相关
    随机的背景图案
    将视频做为网页背景 超炫!
    gunicorn部署Flask服务
    查看mysql数据库及表编码格式
    查看修改mysql编码方式
    【ssm整合打印sql语句】
    【mybatis在控制台打印sql语句配置】
    【mybatis 的foreach的用法】
  • 原文地址:https://www.cnblogs.com/19992147orz/p/6291027.html
Copyright © 2011-2022 走看看