BZOJ 4736 温暖会指引我们前行 LCT+最优生成树+并查集

题目链接:http://uoj.ac/problem/274

题意概述:

没什么好概述的......概述了题意就知道怎么做了......

分析:

就是用lct维护最大生成树。

然后如果去UOJ上面交发现如果不用并查集判断连通性就要T?!

然后我就默默改了并查集。。。(hash表并查集输入输出占据了一半的行数?!)

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<cstdlib>
  5 #include<algorithm>
  6 #include<cmath>
  7 #include<queue>
  8 #include<set>
  9 #include<map>
 10 #include<vector>
 11 #include<cctype>
 12 #define inf 1e9+5
 13 using namespace std;
 14 const int maxm=300005;
 15
 16 int N,M;
 17 struct edge{ int u,v; }E[maxm];
 18 struct union_find{
 19     static const int maxn=100005;
 20     int pa[maxn],stk[maxn],top;
 21     void initial(int n){ for(int i=1;i<=n;i++) pa[i]=i; }
 22     int find(int x){
 23         while(x!=pa[x]) stk[++top]=x,x=pa[x];
 24         while(top) pa[stk[top--]]=x;
 25         return x;
 26     }
 27     bool judge(int x,int y){ return find(x)==find(y); }
 28     void merge(int x,int y){ pa[find(x)]=find(y); }
 29 }uf;
 30 struct Link_Cut_Tree{
 31     static const int maxn=400005;
 32     int ch[maxn][2],fa[maxn],sum[maxn],w[maxn],mn[maxn],t[maxn];
 33     bool rev[maxn];
 34     Link_Cut_Tree(){ mn[0]=inf; }
 35     void link(int x,int d,int y){ ch[x][d]=y,fa[y]=x; }
 36     bool isrt(int x){ return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x; }
 37     void pushup(int now){
 38         sum[now]=sum[ch[now][0]]+sum[ch[now][1]]+w[now];
 39         mn[now]=min(t[now],min(mn[ch[now][0]],mn[ch[now][1]]));
 40     }
 41     void pushdown(int now){
 42         if(!rev[now]) return;
 43         rev[ch[now][0]]^=1,swap(ch[ch[now][0]][0],ch[ch[now][0]][1]);
 44         rev[ch[now][1]]^=1,swap(ch[ch[now][1]][0],ch[ch[now][1]][1]);
 45         rev[now]=0;
 46     }
 47     void rot(int x){
 48         int y=fa[x],z=fa[y];
 49         pushdown(y); pushdown(x);
 50         int d=x==ch[y][0];
 51         if(!isrt(y)) link(z,ch[z][1]==y,x); fa[x]=z;
 52         link(y,d^1,ch[x][d]);
 53         link(x,d,y);
 54         pushup(y); pushup(x);
 55     }
 56     void splay(int x){
 57         pushdown(x);
 58         while(!isrt(x)){
 59             int y=fa[x],z=fa[y];
 60             if(!isrt(y)) rot((ch[z][0]==y)==(ch[y][0]==x)?y:x);
 61             rot(x);
 62         }
 63     }
 64     void access(int x){
 65         int y=0;
 66         while(x){
 67             splay(x); ch[x][1]=y; pushup(x);
 68             y=x,x=fa[x];
 69         }
 70     }
 71     void mroot(int x){
 72         access(x); splay(x);
 73         rev[x]^=1,swap(ch[x][0],ch[x][1]);
 74     }
 75     void Link(int x,int y,int id,int w1,int w2){
 76         mroot(x); mroot(y);
 77         w[N+id]=sum[N+id]=w1,t[N+id]=mn[N+id]=w2;
 78         fa[x]=fa[y]=N+id;
 79     }
 80     void Cut(int id,int x,int y){
 81         mroot(N+id); access(N+id);
 82         splay(x); fa[x]=0;
 83         splay(y); fa[y]=0;
 84     }
 85     int query1(int x,int y){
 86         mroot(y); access(x); splay(x);
 87         return mn[x];
 88     }
 89     int query2(int x,int y){
 90         mroot(y); access(x); splay(x);
 91         return sum[x];
 92     }
 93 }lct;
 94 struct Hash{
 95     static const int maxn=300005;
 96     static const int mo=1000029;
 97     int np,first[mo],next[maxn],id[maxn],val[maxn];
 98     void ins(int p,int t){
 99         int i=t%mo;
100         next[++np]=first[i],first[i]=np;
101         id[np]=p,val[np]=t;
102     }
103     int find(int t){
104         int i=t%mo;
105         for(int p=first[i];p;p=next[p])
106             if(val[p]==t) return id[p];
107         return -1;
108     }
109 }hash;
110
111 void _scanf(int &x)
112 {
113     x=0;
114     char c=getchar();
115     while(c<‘0‘||c>‘9‘) c=getchar();
116     while(c>=‘0‘&&c<=‘9‘) x=x*10+c-‘0‘,c=getchar();
117 }
118 void _scanf(char *s)
119 {
120     int cnt=0;
121     char c=getchar();
122     while(!isalpha(c)) c=getchar();
123     while(isalpha(c)) s[cnt++]=c,c=getchar();
124     s[cnt]=‘\0‘;
125 }
126 int out_cnt,out[15];
127 void _printf(int x)
128 {
129     if(x<0) putchar(‘-‘),x=-x;
130     out[++out_cnt]=x%10,x/=10;
131     while(x) out[++out_cnt]=x%10,x/=10;
132     while(out_cnt) putchar(‘0‘+out[out_cnt--]);
133     putchar(‘\n‘);
134 }
135 void work()
136 {
137     _scanf(N);_scanf(M);
138     uf.initial(N);
139     for(int i=1;i<=N;i++) lct.t[i]=lct.mn[i]=inf;
140     char op[10];
141     int id,u,v,t,l,x;
142     for(int i=1;i<=M;i++){
143         _scanf(op);
144         if(op[0]==‘f‘){
145             _scanf(id);_scanf(u);_scanf(v);_scanf(t);_scanf(l);
146             u++,v++,id++;
147             E[id]=(edge){u,v};
148             hash.ins(id,t);
149             if(uf.judge(u,v)){
150                 x=lct.query1(u,v);
151                 if(x<t){
152                     x=hash.find(x);
153                     lct.Cut(x,E[x].u,E[x].v);
154                     lct.Link(u,v,id,l,t);
155                 }
156             }
157             else{
158                 lct.Link(u,v,id,l,t);
159                 uf.merge(u,v);
160             }
161         }
162         else if(op[0]==‘m‘){
163             _scanf(u);_scanf(v); u++,v++;
164             _printf(uf.judge(u,v)?lct.query2(u,v):-1);
165         }
166         else if(op[0]==‘c‘){
167             _scanf(id);_scanf(l); id++;
168             lct.splay(N+id);
169             lct.w[N+id]=l;
170         }
171     }
172 }
173 int main()
174 {
175     work();
176     return 0;
177 }

原文地址:https://www.cnblogs.com/KKKorange/p/8728046.html

时间: 2024-07-29 03:16:04

BZOJ 4736 温暖会指引我们前行 LCT+最优生成树+并查集的相关文章

bzoj 4736 /uoj274【清华集训2016】温暖会指引我们前行 lct

[清华集训2016]温暖会指引我们前行 统计 描述 提交 自定义测试 寒冬又一次肆虐了北国大地 无情的北风穿透了人们御寒的衣物 可怜虫们在冬夜中发出无助的哀嚎 “冻死宝宝了!” 这时 远处的天边出现了一位火焰之神 “我将赐予你们温暖和希望!” 只见他的身体中喷射出火焰之力 通过坚固的钢铁,传遍了千家万户 这时,只听见人们欢呼 “暖气来啦!” 任务描述 虽然小R住的宿舍楼早已来了暖气,但是由于某些原因,宿舍楼中的某些窗户仍然开着(例如厕所的窗户),这就使得宿舍楼中有一些路上的温度还是很低. 小R的

【UOJ274】【清华集训2016】温暖会指引我们前行 LCT

[UOJ274][清华集训2016]温暖会指引我们前行 任务描述 虽然小R住的宿舍楼早已来了暖气,但是由于某些原因,宿舍楼中的某些窗户仍然开着(例如厕所的窗户),这就使得宿舍楼中有一些路上的温度还是很低. 小R的宿舍楼中有n个地点和一些路,一条路连接了两个地点,小R可以通过这条路从其中任意一个地点到达另外一个地点.但在刚开始,小R还不熟悉宿舍楼中的任何一条路,所以他会慢慢地发现这些路,他在发现一条路时还会知道这条路的温度和长度.每条路的温度都是互不相同的. 小R需要在宿舍楼中活动,每次他都需要从

BZOJ 1370: [Baltic2003]Gang团伙(luogu 1892)(种类并查集)

题面: bzoj题面有误,还是看luogu的吧 https://www.luogu.org/problemnew/show/P1892 题解: 种类并查集.. 因为有敌人的敌人是朋友这个条件,所以需要一个中转点.. 因此,将每个点拆成两个点,一个是朋友点,另一个是敌人点.当读到A与B是朋友时,就将A与B所对应的朋友点并集:当读到两个点是敌人的时候,就将A点所对应的敌人点与B所对应的朋友点并集,将A所对应的朋友点和B所对应的敌人点并集. 代码: #include<bits/stdc++.h> u

【BZOJ4736】温暖会指引我们前行(LCT)

题意:有一张图,每条边有一个不同的编号,长度和权值,维护以下操作: 1.加边 2.修改边长 3.询问两点之间在最小权值最大的前提下的唯一路径长度 n<=100000 m<=300000 思路:RYZ作业 BZOJ上有四组数据的输入不完整,输出没问题 LCT维护最大生成树,维护子树和即可和子树中权值最小的位置即可 1 var t:array[0..700000,0..1]of longint; 2 sum:array[0..700000]of int64; 3 f:array[1..700000

UOJ274 [清华集训2016] 温暖会指引我们前行 【LCT】【最大生成树】

题目分析: 差评,最大生成树裸题.hack数据还卡常. 代码: 1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int maxn = 402000; 5 6 struct LCT{ 7 int fa[maxn],lazy[maxn],ch[maxn][2],d1[maxn],d2[maxn]; 8 int val[maxn],tot[maxn],num; 9 stack<int> sta; 10 void pus

UOJ 274 【清华集训2016】温暖会指引我们前行 ——Link-Cut Tree

魔法森林高清重置, 只需要维护关于t的最大生成树,然后链上边权求和即可. 直接上LCT 调了将近2h 吃枣药丸 #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (int i=j;i<=k;++i) #define D(i,j,k) for (int i=j;i&g

[UOJ274]温暖会指引我们前行

看春晚不如写题... 第一次写维护边权的题,因为懒所以没学边权lct,写的是插入虚点存边权,但我猜两种写法的效率应该差不多 要求最低温度尽量高,所以只能走最高温度生成树上的边,用lct维护就行了 lct维护最大生成树,每加一条边$\left(x,y,T\right)$,如果两边不连通就直接连,如果连通且树上$x\rightarrow y$的最低温度$\geq T$,那么不用加边,否则删掉树上路径最低温的边,加入新边 个人觉得这种插入虚点维护边权的写法挺方便的 #include<stdio.h>

[清华集训] 温暖会指引我们前行

同样是LCT维护一个类似最大生成树的东西. 题目链接:戳我 emmm其实我在uoj上过不去,加的数据我TLE了...... 关于push_up的小trick:初始化的时候给0节点也初始化成最大值,然后push_up的时候不用管自己的左右儿子是否为空,直接返回左右儿子中比较小的一个就可以了,然后再和自己作比较.qwqwq 代码如下: #include<iostream> #include<cstdio> #include<cstring> #include<algo

【BZOJ 3376】[Usaco2004 Open]Cube Stacking 方块游戏 带权并查集

这道题一开始以为是平衡树结果发现复杂度过不去,然后发现我们一直合并而且只是记录到最低的距离,那么就是带权并查集了,带权并查集的权一般是到根的距离,因为不算根要好打,不过还有一些其他的,具体的具体打. #include <cstdio> #include <cstring> const int N=30050; int h[N],f[N],size[N]; char s[2]; inline int find(int x){ if(f[x]==x)return x; int temp