BZOJ3669 (动态树)

Problem 魔法森林 (NOI2014)

题目大意

  给n个点,m条边的无向图,每条边有两个权值a,b。

  求一条从1-->n的路径,使得这条路径上max(a)+max(b)最小。输出最小值即可。

解题分析

  将边按照权值a从小到大排序后,依次加边,用lct维护一棵最小生成树。

  具体做法是如果所加边u-->v导致形成了一个环,那么比较一下u-->v路径中的最大值和这条边的b权值大小,来决定取那条边。

  处理边权的一个做法,将每条边看成一个新的点,向其两端的点连边。

参考程序

  1 #include <map>
  2 #include <set>
  3 #include <stack>
  4 #include <queue>
  5 #include <cmath>
  6 #include <ctime>
  7 #include <string>
  8 #include <vector>
  9 #include <cstdio>
 10 #include <cstdlib>
 11 #include <cstring>
 12 #include <cassert>
 13 #include <iostream>
 14 #include <algorithm>
 15 #pragma comment(linker,"/STACK:102400000,102400000")
 16 using namespace std;
 17
 18 #define N 200008
 19 #define E 400008
 20 #define LL long long
 21 #define lson l,m,rt<<1
 22 #define rson m+1,r,rt<<1|1
 23 #define clr(x,v) memset(x,v,sizeof(x));
 24 #define bitcnt(x) __builtin_popcount(x)
 25 #define rep(x,y,z) for (int x=y;x<=z;x++)
 26 #define repd(x,y,z) for (int x=y;x>=z;x--)
 27 const int mo  = 1000000007;
 28 const int inf = 0x3f3f3f3f;
 29 const int INF = 2000000000;
 30 /**************************************************************************/
 31 int n,m;
 32 int fa[N],val[N],mx[N],rev[N],c[N][2],st[N];
 33
 34 struct line{
 35     int u,v,a,b;
 36     bool operator < (const line &k) const{
 37         return a<k.a;
 38     }
 39 }eg[E];
 40 bool isroot(int k){
 41     return c[fa[k]][0]!=k && c[fa[k]][1]!=k;
 42 }
 43 void pushup(int x){
 44     int l=c[x][0],r=c[x][1];
 45     mx[x]=x;
 46     if  (val[mx[l]]>val[mx[x]]) mx[x]=mx[l];
 47     if  (val[mx[r]]>val[mx[x]]) mx[x]=mx[r];
 48 }
 49 void pushdown(int x){
 50     int l=c[x][0],r=c[x][1];
 51     if (rev[x]){
 52         if (l) rev[l]^=1;
 53         if (r) rev[r]^=1;
 54         rev[x]^=1;
 55         swap(c[x][0],c[x][1]);
 56     }
 57 }
 58 void rotate(int x){
 59     int y=fa[x],z=fa[y],l,r;
 60     if (c[y][0]==x) l=0; else l=1; r=l^1;
 61     if (!isroot(y)){
 62         if (c[z][0]==y) c[z][0]=x; else c[z][1]=x;
 63     }
 64     fa[x]=z; fa[y]=x; fa[c[x][r]]=y;
 65     c[y][l]=c[x][r]; c[x][r]=y;
 66     pushup(y); pushup(x);
 67 }
 68 void splay(int x){
 69     int top=0; st[++top]=x;
 70     for (int i=x;!isroot(i);i=fa[i]) st[++top]=fa[i];
 71     while (top) pushdown(st[top--]);
 72     while (!isroot(x)){
 73         int y=fa[x],z=fa[y];
 74         if (!isroot(y)){
 75             if (c[y][0]==x^c[z][0]==y) rotate(x);
 76             else rotate(y);
 77         }
 78         rotate(x);
 79     }
 80 }
 81 void access(int x){
 82     int t=0;
 83     while (x){
 84         splay(x);
 85         c[x][1]=t;
 86         pushup(x);
 87         t=x; x=fa[x];
 88     }
 89 }
 90 void rever(int x){
 91     access(x); splay(x); rev[x]^=1;
 92 }
 93 void link(int u,int v){
 94     rever(u); fa[u]=v;
 95 }
 96 void cut(int u,int v){
 97     rever(u); access(v); splay(v); fa[c[v][0]]=0; c[v][0]=0; pushup(v);
 98 }
 99 int find(int u){
100     access(u); splay(u);
101     while (c[u][0]) u=c[u][0];
102     return u;
103 }
104 int query(int u,int v){
105     rever(u); access(v); splay(v); return mx[v];
106 }
107
108 int main(){
109     scanf("%d%d",&n,&m);
110     rep(i,1,m) scanf("%d%d%d%d",&eg[i].u,&eg[i].v,&eg[i].a,&eg[i].b);
111     sort(eg+1,eg+m+1);
112     int ans=INF;
113     rep(i,1,m){
114         int u=eg[i].u,v=eg[i].v,a=eg[i].a,b=eg[i].b;
115         int flag=1;
116         if (find(u)==find(v)){
117             int t=query(u,v);
118             if (b<val[t]){
119                 cut(t,eg[t-n].u);
120                 cut(t,eg[t-n].v);
121             }
122             else flag=0;
123         }
124         if (flag) {
125             val[i+n]=b; mx[n+i]=n+i;
126             link(i+n,u);
127             link(i+n,v);
128         }
129         if (find(1)==find(n)){
130             int t=query(1,n);
131             ans=min(ans,val[t]+a);
132         }
133     }
134     printf("%d\n",ans==INF?-1:ans);
135 }

时间: 2024-10-23 02:34:07

BZOJ3669 (动态树)的相关文章

对于动态树 (Link-Cut-Tree, LCT) 的理解与总结

原文链接http://www.cnblogs.com/zhouzhendong/p/8424570.html 对于动态树 $(Link-Cut-Tree, LCT)$ 的理解与总结 问题模型 有$n$个节点,每个节点有权值$v_i$,现在有$m$个操作,操作有可能是以下$4$种类型: $1$   -   连接两个节点 $2$   -   断开两个节点之间的边 $3$   -   修改某一个节点的权值 $4$   -   询问两点之间的节点权值和 保证操作和询问合法,并且输入数据保证任何时刻图中不

luoguP3690 【模板】Link Cut Tree (动态树)[LCT]

题目背景 动态树 题目描述 给定N个点以及每个点的权值,要你处理接下来的M个操作.操作有4种.操作从0到3编号.点从1到N编号. 0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和.保证x到y是联通的. 1:后接两个整数(x,y),代表连接x到y,若x到Y已经联通则无需连接. 2:后接两个整数(x,y),代表删除边(x,y),不保证边(x,y)存在. 3:后接两个整数(x,y),代表将点X上的权值变成Y. 输入输出格式 输入格式: 第1行两个整数,分别为N和M,代表点数和操

bzoj 2631: tree 动态树+常数优化

2631: tree Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1716  Solved: 576[Submit][Status] Description 一棵n个点的树,每个点的初始权值为1.对于这棵树有q个操作,每个操作为以下四种操作之一:+ u v c:将u到v的路径上的点的权值都加上自然数c:- u1 v1 u2 v2:将树中原有的边(u1,v1)删除,加入一条新边(u2,v2),保证操作完之后仍然是一棵树:* u v c:将u到v的

动态树 Link-Cut Trees

动态树 动态树问题, 即要求我们维护一个由若干棵子结点无序的有根树组成的森林. 要求这个数据结构支持对树的分割.合并,对某个点到它的根的路径的某些操作,以及对某个点的子树进行的某些操作. 在这里我们考虑一个简化的动态树问题,它只包含对树的形态的操作和对某个点到根的路径的操作: 维护一个数据结构,支持以下操作: • MAKE TREE() — 新建一棵只有一个结点的树. • CUT(v) — 删除 v 与它的父亲结点 parent(v) 的边,相当于将点 v 的子树分离了出来. • JOIN(v,

extjs动态树 动态grid 动态列

由于项目需要做一个动态的extjs树.列等等,简而言之,就是一个都是动态的加载功能, 自己琢磨了半天,查各种资料,弄了将近两个星期,终于做出来了 首先,想看表结构,我的这个功能需要主从两张表来支持 代码目录表: CREATE TABLE SYS_T01_CODECONTENT ( ID NUMBER NOT NULL, PID NUMBER NOT NULL, TABLENAME VARCHAR2(50 BYTE), ZH_CN VARCHAR2(200 BYTE), ENABLE CHAR(1

bzoj2243 [SDOI2011]染色 动态树

#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 110000 int pre[N],ch[N][2]; int e[N],ne[N*2],v[N*2]; int nn,m; int col[N]; int lc[N],sm[N],rc[N],num[N]; int rt[N],n; int qu[N

【bzoj3924】[Zjoi2015]幻想乡战略游戏 动态树分治

题目描述 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和别人打仗了. 在打仗之前,幽香现在面临一个非常基本的管理问题需要解决. 整个地图是一个树结构,一共有n块空地,这些空地被n-1条带权边连接起来,使得每两个点之间有一条唯一的路径将它们连接起来.在游戏中,幽香可能在空地上增加或者减少一些军队.同时,幽香可以在一个空地上放置一个补给站. 如果补给站在点u上,并

如何利用FineReport制作动态树报表

在对数据字段进行分类管理时,利用动态树折叠数据是一个很好的方法,也就是点击数据前面的加号才展开对应下面的数据,如下图.那这样的效果在制作报表时该如何实现呢? 下面以报表工具FineReport为例介绍. 思路: 通过将模版设置为组织树报表,然后通过设置树节点按钮,最好通过数据分析预览或者form表单预览即可查看效果. 步骤: 1.  初步建立模板 建立模板就相当于建立一个excel的sheet,只不过是cpt的形式.把相应的字段拖到单元格内. 2.  增加树节点按钮 通过设置树节点按钮来实现折叠

动态树学习(留坑)

做了做鞍山网络赛的题,上来就不自量力的去做1006Tree http://acm.hdu.edu.cn/showproblem.php?pid=5002,特征非常明显的动态树.苦调2小时无果.其实还是熟练度不够,否则应该可以慢慢磨出来的.巨不爽,做的再多,比赛搞不出来,等于不会. 决定再学高级数据结构(主要动态树),不知道是第几次重新学了,QTREE系列和那几道历年省选题提交量都已刷屏. 学完,争取把http://www.lydsy.com/JudgeOnline/problem.php?id=

【bzoj3589】动态树 树链剖分+线段树

题目描述 别忘了这是一棵动态树, 每时每刻都是动态的. 小明要求你在这棵树上维护两种事件 事件0:这棵树长出了一些果子, 即某个子树中的每个节点都会长出K个果子. 事件1:小明希望你求出几条树枝上的果子数. 一条树枝其实就是一个从某个节点到根的路径的一段. 每次小明会选定一些树枝, 让你求出在这些树枝上的节点的果子数的和. 注意, 树枝之间可能会重合, 这时重合的部分的节点的果子只要算一次. 输入 第一行一个整数n(1<=n<=200,000), 即节点数. 接下来n-1行, 每行两个数字u,