• 刷题总结——棘手的操作(bzoj2333)


    题目:

    题目背景

    SCOI2011 DAY2 T1

    题目描述

    有 N 个节点,标号从 1 到 N ,这 N 个节点一开始相互不连通。第i个节点的初始权值为 a[i] ,接下来有如下一些操作:
    U x y:     加一条边,连接第 x 个节点和第 y 个节点
    A1 x v:    将第 x 个节点的权值增加 v
    A2 x v:    将第 x 个节点所在的连通块的所有节点的权值都增加 v
    A3 v:      将所有节点的权值都增加 v
    F1 x:      输出第 x 个节点当前的权值
    F2 x:      输出第 x 个节点所在的连通块中,权值最大的节点的权值
    F3:        输出所有节点中,权值最大的节点的权值

    输入格式

    输入的第一行是一个整数 N ,代表节点个数。
    接下来一行输入 N 个整数,a[1], a[2], …, a[N],代表 N 个节点的初始权值。
    再下一行输入一个整数 Q ,代表接下来的操作数。
    最后输入 Q 行,每行的格式如题目描述所示。

    输出格式

    对于操作 F1, F2, F3,输出对应的结果,每个结果占一行。

    样例数据 1

    输入  [复制]

     

    0 0 0 

    A1 3 -20 
    A1 2 20 
    U 1 3 
    A2 1 10 
    F1 3 
    F2 3 
    A3 -10 
    F3

    输出

    -10 
    10 
    10

    备注

    【数据范围】
    对于 30% 的数据,保证 N<=100,Q<=10000
    对于 80% 的数据,保证 N<=100000,Q<=100000
    对于 100% 的数据,保证 N<=300000,Q<=300000
    对于所有的数据,保证输入合法,并且 -1000<=v, a[1], a[2], …, a[N]<=1000

    题解:

    这道题可以用可并堆或者线段树来写····

    然而如果用可并堆得话得会删除特定的点的操作··然而··我一直认为如果有删除特定的点的操作还不如用splay···

    然后我就打了2个小时的splay····最后写不出来弃疗了·····这道题用可并堆做出来的人是真正的勇士·····

    也从这道题中发现了自己代码能力的不足··一是粗心大意···二是不懂得简化代码··搞得写到最后脑袋发蒙·····以后多看看那些写得简洁的人的代码····

    然后我就用线段树来写了··下面将线段树的方法:

    其实用线段树写的话最重要的是要维护一个dfs序···在我们进行离线操作后dfs出来的dfs序必须保证:任意时间所有在同一个并查集里的点的dfs序是连续的···

    怎么做到呢?有两点:

    第一点:我们离线时侯的建边的顺序必须是和我们在离线后dfs时的顺序是一致的

    打个比方···题目中先是连1,2的边··后连1,3的边··那么我们在dfs时候必须先走1,2的边····

    要做到这一点很简单··考虑到临接表加边的顺序与dfs时的顺序是反的···因此我们每次不直接加边··先将边保存起来···最后将所有边倒着加入即可······

    第二点:dfs顺序必须和加边的顺序一致

    依然举上面的例子···如果我们连了2,1的边···那么我们必须保证先dfs2这个点,但如果按正常顺序dfs,我们会先枚举到1这个点,如果1在连了21之后与其他点连了边··直接dfs就会发生错误····

    所以我们可以将1打个标记···在枚举到1的时候直接略过它··这样就可以保证会先dfs到2,再dfs到1···与1相连的其他点也会被dfs到····换句话说··如果连了一条边AB,我们要给B打一个标记····保证dfs时先dfs到点A,再dfs到点B

    解决了dfs序的顺序后接下来就是线段树的基础操作了

    代码:

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cmath>
    #include<ctime>
    #include<cctype>
    #include<cstring>
    #include<string>
    #include<algorithm>
    using namespace std;
    const int N=3e5+5;
    const int inf=0x3f3f3f3f;
    struct node
    {
      int x,y,op;
    }q[N];
    struct node1
    {
      int from,to;
    }e[N];
    int dfn[N],last[N],tree[N*5],father[N],tag[N*5],n,m,num[N],val[N],fst[N],go[N],nxt[N],tot,to,cnt,tol,pre[N];
    bool jud[N]; 
    inline void comb(int a,int b)
    {
      nxt[++tot]=fst[a],fst[a]=tot,go[tot]=b;
    }
    inline int getfa(int u)
    {
      if(father[u]==u)  return u;
      else return father[u]=getfa(father[u]);
    }
    inline int R()
    {
      char c;int f=0,i=1;
      for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());
      if(c=='-')  c=getchar(),i=-1;
      for(;c<='9'&&c>='0';c=getchar())
        f=(f<<3)+(f<<1)+c-'0';
      return f*i;
    }
    inline void dfs(int u)
    {
      last[u]=dfn[u]=++cnt;
      for(int e=fst[u];e;e=nxt[e])  dfs(go[e]);
    }
    inline void add(int k,int v)
    {
      tree[k]+=v;tag[k]+=v;
    }
    inline void pushdown(int k)
    {
      if(tag[k])
      {
        add(k*2,tag[k]);
        add(k*2+1,tag[k]);
        tag[k]=0;
      }
    }
    inline void build(int k,int l,int r)
    {
      if(l==r)
      {
        tree[k]=val[l];return;
      }
      int mid=(l+r)/2;
      build(k*2,l,mid);build(k*2+1,mid+1,r);
      tree[k]=max(tree[k*2],tree[k*2+1]);
      return;
    } 
    inline void modify(int k,int l,int r,int x,int y,int v)
    {
      if(l>=x&&r<=y)
      {
        add(k,v);return;
      }
      int mid=(l+r)/2;
      pushdown(k);
      if(x<=mid)  modify(k*2,l,mid,x,y,v);
      if(y>mid)  modify(k*2+1,mid+1,r,x,y,v);
      tree[k]=max(tree[k*2],tree[k*2+1]);
    }
    inline int query(int k,int l,int r,int x,int y)
    {
      if(l>=x&&r<=y)
        return tree[k];
      int mid=(l+r)/2;int temp=-inf;
      pushdown(k);
      if(x<=mid)  temp=max(temp,query(k*2,l,mid,x,y));
      if(y>mid)  temp=max(temp,query(k*2+1,mid+1,r,x,y));
      return temp;
    }
    int main()
    {
      //freopen("a.in","r",stdin);
      //freopen("a.out","w",stdout);
      memset(tree,-inf,sizeof(tree));
      n=R();for(int i=1;i<=n;i++)  num[i]=R(),father[i]=i;
      m=R();char s[5];memset(jud,true,sizeof(jud));
      for(int i=1;i<=m;i++) 
      {
        scanf("%s",s);
        if(s[0]=='U')
        {
          q[i].op=1;q[i].x=R(),q[i].y=R(); 
          int a=getfa(q[i].x),b=getfa(q[i].y);
          if(a!=b)  father[a]=b,jud[a]=false,e[++tol].from=b,e[tol].to=a;
        }
        else if(s[0]=='A')
        {
          if(s[1]=='1')  q[i].op=2,q[i].x=R(),q[i].y=R();  
          if(s[1]=='2')  q[i].op=3,q[i].x=R(),q[i].y=R();
          if(s[1]=='3')  q[i].op=4,q[i].x=R();
        }
        else if(s[0]=='F')
        {
          if(s[1]=='1')  q[i].op=5,q[i].x=R();
          if(s[1]=='2')  q[i].op=6,q[i].x=R();
          if(s[1]=='3')  q[i].op=7;
        }
      }
      for(int i=tol;i;i--)  comb(e[i].from,e[i].to);
      for(int i=1;i<=n;i++)  
      { 
          father[i]=i;
          if(!dfn[i]&&jud[i])  
            dfs(i);
      }
      for(int i=1;i<=n;i++)  pre[i]=dfn[i],val[dfn[i]]=num[i];build(1,1,n);
      for(int i=1;i<=m;i++)
      {
        if(q[i].op==1)
        {
          int a=getfa(q[i].x),b=getfa(q[i].y);
          if(a!=b)  father[a]=b,dfn[b]=max(dfn[b],dfn[a]),last[b]=min(last[b],last[a]);
        }
        if(q[i].op==2)
        {
          int a=q[i].x,b=q[i].y;
          modify(1,1,n,pre[a],pre[a],b);
        }
        if(q[i].op==3)
        {
          int a=getfa(q[i].x),b=q[i].y;
          modify(1,1,n,last[a],dfn[a],b);
        }
        if(q[i].op==4)
        {
          int a=q[i].x;
          modify(1,1,n,1,n,a);
        }
        if(q[i].op==5)
        {
          int a=q[i].x;
          printf("%d
    ",query(1,1,n,pre[a],pre[a]));
        }
        if(q[i].op==6)
        {
          int a=getfa(q[i].x);
          printf("%d
    ",query(1,1,n,last[a],dfn[a]));
        }
        if(q[i].op==7)
          printf("%d
    ",query(1,1,n,1,n));    
      }
      return 0;
    }
  • 相关阅读:
    linux下使用tar命令
    ContentType和@ResponseBody
    ActiveMQ两种模式PTP和PUB/SUB<转>
    Postgresql分表与优化
    PostgreSQL存储过程<转>
    PostgreSQL Table Partitioning<转>
    Postgresql查询表的大小
    Postgresql添加/删除触发器示例
    Android TextView 支持的HTML标签
    我只是一直很努力
  • 原文地址:https://www.cnblogs.com/AseanA/p/7606178.html
Copyright © 2020-2023  润新知