【bzoj4736/uoj#274】[清华集训2016]温暖会指引我们前行 语文题+LCT
2017-12-19 11:12
302 查看
题目描述
http://uoj.ac/problem/274
题解
语文题+LCT
对于这种语文题建议还是自己读题好一些。。。
读懂题后发现:由于温度互不相同,最大生成树上的路径必须走(不走的话温度大的边少了,字典序一定会更小),并且不能多走边(因为多走的话串会变长,长度大反而亏),因此答案就是最大生成树上的路径。
因此使用LCT维护最大生成树即可。维护两点之间权值最小的边。加边时如果已经连通,则判断加的边与最小的边那个大,如果新加的边大则删掉原来最小的边,加入新边。
至于边长度的处理,可以新建一个虚点代表这条边,点权位相应边长度。加边时连接虚点和x、虚点和y即可。
时间复杂度 $O(LCT·n\log n)$
http://uoj.ac/problem/274
题解
语文题+LCT
对于这种语文题建议还是自己读题好一些。。。
读懂题后发现:由于温度互不相同,最大生成树上的路径必须走(不走的话温度大的边少了,字典序一定会更小),并且不能多走边(因为多走的话串会变长,长度大反而亏),因此答案就是最大生成树上的路径。
因此使用LCT维护最大生成树即可。维护两点之间权值最小的边。加边时如果已经连通,则判断加的边与最小的边那个大,如果新加的边大则删掉原来最小的边,加入新边。
至于边长度的处理,可以新建一个虚点代表这条边,点权位相应边长度。加边时连接虚点和x、虚点和y即可。
时间复杂度 $O(LCT·n\log n)$
#include <cstdio> #include <algorithm> #define N 400010 using namespace std; typedef pair<int , int> pr; int f , v , w , fa , c[2] , si , sum , rev , px , py ; pr mn ; char str[10]; int find(int x) { return x == f[x] ? x : f[x] = find(f[x]); } inline void pushup(int x) { si[x] = si[c[0][x]] + si[c[1][x]] + 1; mn[x] = min(pr(v[x] , x) , min(mn[c[0][x]] , mn[c[1][x]])); sum[x] = sum[c[0][x]] + sum[c[1][x]] + w[x]; } inline void pushdown(int x) { if(rev[x]) { swap(c[0][c[0][x]] , c[1][c[0][x]]); swap(c[0][c[1][x]] , c[1][c[1][x]]); rev[c[0][x]] ^= 1 , rev[c[1][x]] ^= 1; rev[x] = 0; } } inline bool isroot(int x) { return c[0][fa[x]] != x && c[1][fa[x]] != x; } void update(int x) { if(!isroot(x)) update(fa[x]); pushdown(x); } inline void rotate(int x) { int y = fa[x] , z = fa[y] , l = (c[1][y] == x) , r = l ^ 1; if(!isroot(y)) c[c[1][z] == y][z] = x; fa[x] = z , fa[y] = x , fa[c[r][x]] = y , c[l][y] = c[r][x] , c[r][x] = y; pushup(y) , pushup(x); } inline void splay(int x) { int y , z; update(x); while(!isroot(x)) { y = fa[x] , z = fa[y]; if(!isroot(y)) { if((c[0][y] == x) ^ (c[0][z] == y)) rotate(x); else rotate(y); } rotate(x); } } inline void access(int x) { int t = 0; while(x) splay(x) , c[1][x] = t , pushup(x) , t = x , x = fa[x]; } inline void makeroot(int x) { access(x) , splay(x) , swap(c[0][x] , c[1][x]) , rev[x] ^= 1; } inline void link(int x , int y) { makeroot(x) , fa[x] = y; } inline void split(int x , int y) { makeroot(x) , access(y) , splay(y); } inline void cut(int x , int y) { split(x , y) , fa[x] = c[0][y] = 0 , pushup(y); } int main() { int n , m , i , id , x , y , z , t , l; scanf("%d%d" , &n , &m); mn[0] = pr(1 << 30 , 0); for(i = 1 ; i <= n ; i ++ ) f[i] = i , mn[i] = pr(v[i] = 1 << 30 , i) , sum[i] = w[i] = 0 , si[i] = 1; while(m -- ) { scanf("%s" , str); if(str[0] == 'f') { scanf("%d%d%d%d%d" , &id , &x , &y , &t , &l) , x ++ , y ++ , id ++ ;; px[id] = x , py[id] = y , mn[id + n] = pr(v[id + n] = t , id + n) , sum[id + n] = w[id + n] = l , si[id + n] = 1; if(find(x) != find(y)) link(id + n , x) , link(id + n , y) , f[f[x]] = f[y]; else { split(x , y); if(mn[y].first < t) z = mn[y].second - n , cut(z + n , px[z]) , cut(z + n , py[z]) , link(id + n , x) , link(id + n , y); } } else if(str[0] == 'm') { scanf("%d%d" , &x , &y) , x ++ , y ++ ; if(find(x) != find(y)) puts("-1"); else split(x , y) , printf("%d\n" , sum[y]); } else scanf("%d%d" , &id , &l) , splay(++id + n) , w[id + n] = l , pushup(id + n); } return 0; }
相关文章推荐
- UOJ274 [清华集训2016] 温暖会指引我们前行 【LCT】【最大生成树】
- UOJ_274_[清华集训2016]温暖会指引我们前行_LCT
- UOJ 274 【清华集训2016】温暖会指引我们前行 ——Link-Cut Tree
- uoj#274. 【清华集训2016】温暖会指引我们前行 //LCT
- UOJ #274. 【清华集训2016】温暖会指引我们前行 [lct]
- 【UOJ274】【清华集训2016】温暖会指引我们前行 LCT
- UOJ#274 BZOJ4736 【清华集训2016】温暖会指引我们前行
- UOJ#274. 【清华集训2016】温暖会指引我们前行
- uoj#274. 【清华集训2016】温暖会指引我们前行
- 【uoj274】【清华集训2016】温暖会指引我们前行
- uoj 279: [清华集训2016]温暖会指引我们前行
- BZOJ 4736/UOJ #274. 【清华集训2016】温暖会指引我们前行 LCT边权操作
- uoj274 温暖会指引我们前行
- 【BZOJ4736】温暖会指引我们前行(LCT)
- [UOJ274]温暖会指引我们前行
- BZOJ4736 温暖会指引我们前行
- [BZOJ4736]温暖会指引我们前行
- uoj279温暖会指引我们前行
- 【BZOJ4736】温暖会指引我们前行(Link-Cut Tree)
- uoj#272. 【清华集训2016】石家庄的工人阶级队伍比较坚强