圆方树模板题.

建出圆方树.

对于每个方点,只维护方点儿子的最小值,不维护方点父亲的值,这样的话每次修改只会改一个方点.

我们需要支持单点修改,链查询,求 lca.

LCT 可以非常方便地维护这些东西,然后如果 lca 是方点的话特判一下方点父亲的点值即可.

code:

#include <cstdio>
#include <algorithm>
#include <set>
#include <vector>
#include <cstring>  #define setI(s) freopen(s".in","r",stdin)
#define setO(s) freopen(s".out","w",stdout)
#define setIO(s) setI(s),setO(s)  using namespace std;   const int N=2e5+5;
const int inf=1e9+2;                     namespace lct {  #define lson s[x].ch[0] #define rson s[x].ch[1] struct data {int ch[2],rev,val,mi,f;         data(int x=inf) { ch[0]=ch[1]=0,val=mi=x; }       }s[N];   int sta[N];     int get(int x) { return s[s[x].f].ch[1]==x; } int isr(int x) { return s[s[x].f].ch[0]!=x&&s[s[x].f].ch[1]!=x; }   void pushup(int x) {  s[x].mi=min(s[x].val,min(s[lson].mi,s[rson].mi));}    void mark(int x) {if(!x) return;   swap(lson,rson),s[x].rev^=1; }    void pushdown(int x) {if(s[x].rev) mark(lson),mark(rson),s[x].rev=0;  }     void rotate(int x) { int old=s[x].f,fold=s[old].f,which=get(x);  if(!isr(old)) s[fold].ch[s[fold].ch[1]==old]=x;     s[old].ch[which]=s[x].ch[which^1];   if(s[old].ch[which]) s[s[old].ch[which]].f=old;   s[x].ch[which^1]=old,s[old].f=x,s[x].f=fold;   pushup(old),pushup(x); }void splay(int x) {int u=x,v=0,fa;   for(sta[++v]=u;!isr(u);u=s[u].f)   sta[++v]=s[u].f;   for(;v;--v) pushdown(sta[v]);   for(u=s[u].f;(fa=s[x].f)!=u;rotate(x))       if(s[fa].f!=u)   rotate(get(fa)==get(x)?fa:x);     }int Access(int x) {  int y=0; for(;x;y=x,x=s[x].f)   splay(x),rson=y,pushup(x);     return y; }void makert(int x) {Access(x),splay(x),mark(x);  }void split(int x,int y) {makert(x),Access(y),splay(y);  }    void link(int x,int y) { s[x].f=y;     }  int get_lca(int x,int y) {    Access(x);      return Access(y); }
};    vector<int>G[N];
int val[N],dfn[N],low[N],S[N],tim,top,tot;
int hd[N],to[N],nex[N],edges,n,m,Q;
int fa[N];
multiset<int>mi[N];
void add(int u,int v)
{nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;
}
void tarjan(int u)
{dfn[u]=low[u]=++tim; S[++top]=u;    for(int i=hd[u];i;i=nex[i]) {int v=to[i];    if(!dfn[v]) {tarjan(v),low[u]=min(low[u],low[v]);            if(low[v]>=dfn[u]) {       ++tot;   G[tot].push_back(u);    G[u].push_back(tot);  for(int x=0;x!=v;--top) {x=S[top];      G[tot].push_back(x); G[x].push_back(tot);      }}}else low[u]=min(low[u],dfn[v]);       }
}
void dfs(int x,int ff)
{     if(ff) lct::link(x,ff); if(x<=n) {    if(ff) mi[ff].insert(val[x]);      lct::s[x].val=lct::s[x].mi=val[x];    }for(int i=0;i<G[x].size();++i) {int y=G[x][i];   if(y!=ff) fa[y]=x,dfs(y,x);    }      if(x>n)  {lct::s[x].val=lct::s[x].mi=*mi[x].begin();  }
}
int main()
{   //setI("input");                    scanf("%d%d%d",&n,&m,&Q);    for(int i=1;i<=n;++i)   scanf("%d",&val[i]);     for(int i=1;i<=m;++i) {int x,y; scanf("%d%d",&x,&y); add(x,y),add(y,x);    }     tot=n;  for(int i=1;i<=n;++i)  if(!dfn[i])  tarjan(i);      dfs(1,0);      val[0]=inf;     for(int i=1;i<=Q;++i) {     char ch[2];   int x,b;  scanf("%s%d%d",ch,&x,&b);   if(ch[0]=='C')  {  lct::splay(x); lct::s[x].val=b;   lct::pushup(x);           if(fa[x]) {mi[fa[x]].erase(mi[fa[x]].lower_bound(val[x]));    mi[fa[x]].insert(b);    lct::splay(fa[x]);    lct::s[fa[x]].val=*mi[fa[x]].begin();         lct::pushup(fa[x]);   }              val[x]=b;    // modify(val[x] -> b)  } else {// query(a,b)      int lca=lct::get_lca(x,b);               if(lca<=n)  lca=0;   lct::split(x,b);     printf("%d\n",min(lct::s[b].mi,val[fa[lca]]));  lct::makert(1);         }     }                 return 0;
}

  

CF487E Tourists (圆方树,LCT)相关推荐

  1. 【学习笔记】圆方树(CF487E Tourists)

    终于学了圆方树啦~\(≧▽≦)/~ 感谢y_immortal学长的博客和帮助 把他的博客挂在这里~ 点我传送到巨佬的博客QwQ! 首先我们来介绍一下圆方树能干什么呢qwq 1.将图上问题简化到树上问题 ...

  2. 【CF487E】Tourists【圆方树】【树链剖分】【multiset】

    题意:给一张 nnn 点 mmm 边的连通无向图,点帯权,qqq 次操作: 修改一个点的权值. 询问两点间所有简单路的最小权值的最小值. n,m,q≤105n,m,q\leq 10^5n,m,q≤10 ...

  3. CF487E Tourists(圆方树+树链剖分)

    洛谷题目传送门 解题思路 不会圆方树的可以看我的博客圆方树学习记录及例题 首先Tarjan寻找点双连通分量,然后建立圆方树,每个方点存这个点双内的最小点权 将圆方树树链剖分之后,对于修改操作,将这个点 ...

  4. 广义圆方树+树链剖分+set(Codeforces Round #278 (Div. 1): E. Tourists)

    前置:双联通分量.圆方树.树链剖分 什是是广义圆方树 圆方树是针对于仙人掌建树,而广义圆方树是针对无向图建树,对于一个无向图 无向图中的所有点 → 广义圆方树中的所有圆点 无向图中的一个双联通分量 → ...

  5. 【YBT2022寒假Day3 C】毒瘤染色(LCT)(圆方树)(容斥)

    毒瘤染色 题目链接:YBT2022寒假Day3 C 题目大意 要你在线实现一个操作: 一开始有 n 个点,没有边,然后操作会给你一条边. 如果保证加了之后这个图还是沙漠就加上. 然后每次加完边之后问你 ...

  6. 圆方树学习记录及例题

    对于一个无向连通图,我们可以通过一些操作使其变成一棵树,然后再在树上操作 这颗树就叫圆方树,具体是怎么样的呢?看下图 这是一个无向连通图 然后找到每一个点双连通分量,并在这个点双里新建一个节点,并且是 ...

  7. 【蒟蒻の笔记】圆方树初识

    圆方树 首先描述一下圆方树: 注:我们把一条边连接两个节点的图也认为是点双连通的. 对于一个无向连通图,对于每个点双连通分量建立一个新的点,新的点作为"方点",原本的点作为&quo ...

  8. [学习笔记]圆方树广义圆方树

    引入 偶尔,我们会遇到一些要在无向图/仙人掌上做的问题,这些问题如果在树上就会比较方便,那么我们就开始考虑能不能把原图等效成一棵树,然后就可以方便地乱搞了? 圆方树就是一种将无向图/仙人掌变成树的数据 ...

  9. 仙人掌圆方树学习笔记

    终于对仙人掌有了一点初步的理解. 仙人掌 仙人掌是什么? 仙人掌是一个无向图. 仙人掌有什么特点? 仙人掌的每条边只属于一个简单环. 下面是一个栗子 有什么用呢? 我们可以先用\(tarjan\)找出 ...

  10. [APIO2018] Duathlon 铁人两项 圆方树,DP

    [APIO2018] Duathlon 铁人两项 LG传送门 圆方树+简单DP. 不会圆方树的话可以看看我的另一篇文章. 考虑暴力怎么写,枚举两个点,答案加上两个点之间的点的个数. 看到题面中的一句话 ...

最新文章

  1. 6个能写进简历的AI项目,有点难,一起来挑战?
  2. docker 使用python 镜像运行python脚本
  3. 【JVM调优】JVM的运行参数
  4. NSArray文件读写
  5. 一站式学习Wireshark(七):Statistics统计工具功能详解与应用
  6. Xenix — 微软与UNIX的短暂爱恋
  7. 21 MM配置-采购-定义采购组
  8. Vue 事件绑定 事件修饰符 条件判断 循环遍历
  9. 昆明职高计算机学校,昆明职高学校,昆明职高学校前十强,昆明职高学校哪些比较好一点 - IT教育频道...
  10. redux-chunk中间件的安装和使用-(二)
  11. FLTK学习笔记4-在FLTK中显示图片(上)
  12. 1000套电子物联网专业毕业设计和电赛设计资料822份
  13. FloydFest 19 大赛冠军歌曲 Roll With Me,使用Peluso话筒录制
  14. 爬动漫“上瘾”之后,放弃午休,迫不及待的用Python薅了腾Xun动漫的数据,啧啧啧
  15. 如何抢功,甩锅,立于不败之地???
  16. “感动阿里”的技术小二刘畅:善良的事情,我身边很多人都在做
  17. 【python】控制鼠标定时移动 防止屏幕锁定 并生成可执行文件exe
  18. 【“BattenSnakexjp4.1”数据结构课程设计报告】
  19. python import ssl失败_Python3.7无法正常导入ssl--ImportError: No module named _ssl
  20. 了解“预编译、编译、汇编、链接”这四个过程对你有很大帮

热门文章

  1. 4pm 方法操datagrid
  2. DBCO-C6-NHS ester,1384870-47-6二苯基环辛炔-碳6-琥珀酰亚胺酯仅用于科研,不用于人体和生产
  3. 记录自己的UCF—Crime代码debug
  4. Acdream 1729 Crime
  5. RabbitMQ消息队列(九):Publisher的消息确认机制
  6. HTML5系列(2)history
  7. ansible模块authorized_key
  8. 第十篇:SpringBoot集成支付宝接口扫码支付
  9. gentoo mysql_gentoo
  10. Offer是否具有法律效力