• bzoj2959: 长跑


      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <cmath>
      5 #include <algorithm>
      6 #define maxn 150005
      7 using namespace std;
      8 
      9 int n,m,val[maxn],tot[maxn],fa[maxn],sum[maxn],son[maxn][2],bel[maxn],bel_[maxn];
     10 bool rev[maxn];
     11 
     12 struct date{
     13     int isroot(int x){
     14         return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;
     15     }
     16     bool which(int x){
     17         return son[fa[x]][1]==x;
     18     }
     19     void update(int x){
     20         sum[x]=tot[x];
     21         if (son[x][0]) sum[x]+=sum[son[x][0]];
     22         if (son[x][1]) sum[x]+=sum[son[x][1]];
     23     }
     24     void pushdown(int x){
     25         if (!rev[x]) return;
     26         swap(son[x][0],son[x][1]),rev[x]^=1;
     27         if (son[x][0]) rev[son[x][0]]^=1;
     28         if (son[x][1]) rev[son[x][1]]^=1;
     29     }
     30     void relax(int x){
     31         if (!isroot(x)) relax(fa[x]);
     32         pushdown(x);
     33     }
     34     void rotata(int x){
     35         int y=fa[x],d=which(x),dd=which(y);
     36         if (!isroot(y)) son[fa[y]][dd]=x; fa[x]=fa[y];
     37         fa[son[x][d^1]]=y,son[y][d]=son[x][d^1];
     38         fa[y]=x,son[x][d^1]=y;
     39         update(y);
     40     }
     41     void splay(int x){
     42         relax(x);
     43         while (!isroot(x)){
     44             if (isroot(fa[x])) rotata(x);
     45             else if (which(x)==which(fa[x])) rotata(fa[x]),rotata(x);
     46             else rotata(x),rotata(x);
     47         }
     48         update(x);
     49     }
     50     int find(int x){
     51         if (bel[x]!=x) bel[x]=find(bel[x]);
     52         return bel[x];
     53     }
     54     int find_(int x){
     55         if (bel_[x]!=x) bel_[x]=find_(bel_[x]);
     56         return bel_[x];
     57     }
     58     void access(int x){
     59         for (int p=0;x;fa[x]=find(fa[x]),x=fa[x]){
     60             splay(x);
     61             son[x][1]=p;
     62             p=x;
     63             update(x);
     64         }
     65     }
     66     void make_root(int x){
     67         access(x);
     68         splay(x);
     69         rev[x]^=1;
     70     }
     71     void link(int x,int y){
     72         make_root(x);
     73         fa[x]=y;
     74     }
     75     void merge(int x,int y){
     76         bel[x]=y;
     77         if (x!=y) tot[y]+=tot[x];
     78         pushdown(x);
     79         if (son[x][0]) merge(son[x][0],y);
     80         if (son[x][1]) merge(son[x][1],y);
     81     }
     82     void build(int x,int y){
     83         if (x==y) return;
     84         x=find(x),y=find(y);
     85         int xx=find_(x),yy=find_(y);
     86         if (xx!=yy) link(x,y),bel_[xx]=yy;
     87         else{
     88             make_root(x),access(y),splay(y),merge(y,y);
     89         }
     90     }
     91     void change(int x,int y){
     92         int t=find(x);
     93         splay(t),tot[t]-=val[x],val[x]=y,tot[t]+=val[x],update(t);
     94     }
     95     void query(int x,int y){
     96         x=find(x),y=find(y);
     97         if (find_(x)!=find_(y)) printf("-1
    ");
     98         else make_root(x),access(y),splay(y),printf("%d
    ",sum[y]);
     99     }
    100 }lct;
    101 
    102 int main(){
    103     freopen("race.in","r",stdin);
    104     freopen("race.out","w",stdout);
    105     memset(rev,0,sizeof(rev));
    106     int op,u,v;
    107     scanf("%d%d",&n,&m);
    108     for (int i=1;i<=n;i++) scanf("%d",&u),val[i]=tot[i]=sum[i]=u,rev[i]=fa[i]=son[i][0]=son[i][1]=0,bel[i]=bel_[i]=i;
    109     while (m--){
    110         scanf("%d%d%d",&op,&u,&v);
    111         if (op==1) lct.build(u,v);
    112         else if (op==2) lct.change(u,v);
    113         else lct.query(u,v);
    114     }
    115     return 0;
    116 }
    View Code

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=2959

    题目大意:给定无向图,有n个节点,初始时节点之间没有边,节点的初始节点权值为val[i],有m个操作:

    1.在a,b之间连一条无向边;

    2.将节点a的权值改为b;

    3.询问操作:给定a,b,要你给图中无向边定向,再寻找一条路径,满足路径上的节点权值之和最大,不一定是简单路径,即每个点可以经过多次,但权值只会算一次,若不存在这样的路径,则输出-1。

    做法:如果没有操作1,我们可以把原图中的边双连通分量缩点,该点的权值为该边双连通分量中节点的权值之和,缩完点后,会变成一个森林,对于操作2与操作3,用树链剖分即可。

    有了操作1,我们会想到用lct来维护,加入一条边后,如果不形成环,就加入,否则,将链上的点缩成一个点,用并查集维护即可。

    注意:access的时候这能把双联通分量的代表点加入splay中,否则答案会重复算,具体见access过程。

    由于这题卡常数,没有删边操作,在判断连通性时不能用find_root(x),应再用一个并查集来维护。

    lct+并查集

  • 相关阅读:
    array_diff()和array_diff_assoc()
    React出现错误:Uncaught TypeError: this.setState is not a function
    predis操作大全
    MacOS下出现-bash: 命令: command not found的解决方法
    OnCreateClient学习总结
    MFC之CSingleDocTemplate构造函数
    CString 的成员函数详解
    MFC 中Invalidate的使用
    CFileFind类的使用总结(转)
    MFC CSplitterWnd的用法
  • 原文地址:https://www.cnblogs.com/OYzx/p/5506775.html
Copyright © 2020-2023  润新知