[XSY 1556] 股神小D LCT维护子树信息

实现

  1
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <cctype>
  6 #include <algorithm>
  7 #include <vector>
  8 using namespace std;
  9 #define F(i, a, b) for (register int i = (a); i <= (b); i++)
 10 #define LL long long
 11 inline int rd(void) {
 12     int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == ‘-‘) f = -1;
 13     int x = 0; for (; isdigit(c); c = getchar()) x = x*10+c-‘0‘; return x*f;
 14 }
 15
 16 const int N = 200005;
 17 const int T = 400005;
 18
 19 int tot;
 20 struct E {
 21     int t, x, y, sign;
 22     friend inline bool operator < (E A, E B) { return A.t != B.t ? A.t < B.t : A.sign < B.sign; }
 23 }Edge[T];
 24
 25 int n, pre[N]; vector<int> g[N];
 26 void Parent(int x) {
 27     for (vector<int>::iterator it = g[x].begin(); it != g[x].end(); it++)
 28         if (pre[x] != *it) {
 29             pre[*it] = x;
 30             Parent(*it);
 31         }
 32 }
 33
 34 #define LC (c[x][0])
 35 #define RC (c[x][1])
 36 int c[N][2], par[N], siz[N], out[N]; LL sum;
 37
 38 inline void Up(int x) { siz[x] = siz[LC] + siz[RC] + out[x] + 1; }
 39 inline bool Root(int x) { return c[par[x]][0] != x && c[par[x]][1] != x; }
 40 inline void Rot(int x) {
 41     int y = par[x], z = par[y];
 42     int L = (c[y][1] == x), R = L^1;
 43
 44     if (!Root(y))
 45         c[z][c[z][1] == y] = x;
 46     par[x] = z;
 47
 48     if (c[x][R] > 0)
 49         par[c[x][R]] = y;
 50     c[y][L] = c[x][R];
 51
 52     c[x][R] = y, par[y] = x;
 53     Up(y), Up(x);
 54 }
 55 inline void Splay(int x) {
 56     for (; !Root(x); Rot(x)) {
 57         int y = par[x], z = par[y];
 58         if (!Root(y)) { (c[y][0] == x) ^ (c[z][0] == y) ? Rot(x) : Rot(y); }
 59     }
 60 }
 61
 62 inline void Expose(int x) {
 63     for (int t = 0; x > 0; t = x, x = par[x]) {
 64         Splay(x);
 65         out[x] += siz[RC];
 66         RC = t;
 67         out[x] -= siz[RC];
 68     }
 69 }
 70
 71 inline void Reorder(int &x, int &y) { if (pre[y] == x) swap(x, y); }
 72 inline void Link(int x, int y) {
 73     // 保证 x 和 y 都是 Splay 的根
 74     Reorder(x, y);
 75     par[x] = y;
 76     out[y] += siz[x];
 77     siz[y] += siz[x];
 78 }
 79 inline void Cut(int x, int y) {
 80     Reorder(x, y);
 81     Expose(x);
 82     Splay(x);
 83     siz[x] -= siz[LC];
 84     par[LC] = 0, LC = 0;
 85 }
 86
 87 void Travel(int x) {
 88     if (!x) return;
 89     Travel(LC);
 90     printf("%d ", x);
 91     Travel(RC);
 92 }
 93 void Print(int x) { Travel(x), puts(""); }
 94
 95 int main(void) {
 96     #ifndef ONLINE_JUDGE
 97         freopen("D.in", "r", stdin);
 98     #endif
 99
100     n = rd();
101     F(i, 1, n-1) {
102         int x = rd(), y = rd(), l = rd(), r = rd();
103         g[x].push_back(y), g[y].push_back(x);
104         Edge[++tot] = (E){l, x, y, +1}, Edge[++tot] = (E){r+1, x, y, -1};
105     }
106     sort(Edge+1, Edge+tot+1);
107
108     Parent(1);
109
110     F(i, 1, n) siz[i] = 1;
111     F(i, 1, tot) {
112         int x = Edge[i].x, y = Edge[i].y, sign = Edge[i].sign;
113         if (sign == +1) {
114             Expose(x);
115             Splay(x);
116             Expose(y);
117             Splay(y);
118             sum += 1LL * siz[x] * siz[y];
119             Link(x, y);
120         }
121         else Cut(x, y);
122     }
123     printf("%lld\n", sum);
124
125     return 0;
126 }
时间: 2024-08-25 23:07:05

[XSY 1556] 股神小D LCT维护子树信息的相关文章

【bzoj4530】[Bjoi2014]大融合 LCT维护子树信息

题目描述 小强要在N个孤立的星球上建立起一套通信系统.这套通信系统就是连接N个点的一个树. 这个树的边是一条一条添加上去的.在某个时刻,一条边的负载就是它所在的当前能够联通的树上路过它的简单路径的数量. 例如,在上图中,现在一共有了5条边.其中,(3,8)这条边的负载是6,因为有六条简单路径2-3-8,2-3-8-7,3-8,3-8-7,4-3-8,4-3-8-7路过了(3,8). 现在,你的任务就是随着边的添加,动态的回答小强对于某些边的负载的询问. 输入 第一行包含两个整数N,Q,表示星球的

【BZOJ3510】首都 LCT维护子树信息+启发式合并

[BZOJ3510]首都 Description 在X星球上有N个国家,每个国家占据着X星球的一座城市.由于国家之间是敌对关系,所以不同国家的两个城市是不会有公路相连的. X星球上战乱频发,如果A国打败了B国,那么B国将永远从这个星球消失,而B国的国土也将归A国管辖.A国国王为了加强统治,会在A国和B国之间修建一条公路,即选择原A国的某个城市和B国某个城市,修建一条连接这两座城市的公路. 同样为了便于统治自己的国家,国家的首都会选在某个使得其他城市到它距离之和最小的城市,这里的距离是指需要经过公

bzoj3510 首都 LCT 维护子树信息+树的重心

题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3510 题解 首先每一个连通块的首都根据定义,显然就是直径. 然后考虑直径的几个性质: 定义:删去这个点以后剩下的连通块最大的最小的点为重心. 一棵树最多只能有两个相邻的直径: 一棵树的重心到一棵树中所有点的距离和最小.(这个也是题目的条件转化为重心的原因) 两棵树的并的重心在两棵树各自的重心的连线上. 一棵树添加或者删除一个节点,树的重心最多只移动一条边的位置. 有了这些性质,我们可以发现,

【LCT维护子树信息】uoj207 共价大爷游长沙

这道题思路方面就不多讲了,主要是通过这题学一下lct维护子树信息. lct某节点u的子树信息由其重链的一棵splay上信息和若干轻儿子子树信息合并而成. splay是有子树结构的,可以在rotate,access的时候由儿子update到父亲,而轻儿子的信息update不上来,需要另外记一下. 记sum[x]为我们要求的子树信息,xu[x]为x的轻儿子的子树信息. (即,xu[x]由轻儿子的sum更新,sum[x]由xu[x]和splay子树上的儿子的sum更新. 这样我们就可以完整地用lct维

Loj 2230. 「BJOI2014」大融合 (LCT 维护子树信息)

链接:https://loj.ac/problem/2230 思路: 设立siz数组保存虚点信息,sum表示总信息 维护子树信息link操作和access操作需要进行一些改动 可参考博客:https://www.cnblogs.com/GXZlegend/p/7061458.html 实现代码; #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include&l

[BJOI2014]大融合 LCT维护子树信息

Code: #include <cstdio> #include <algorithm> #include <cstring> #include <string> using namespace std; void setIO(string a){freopen((a+".in").c_str(),"r",stdin);} #define maxn 100009 #define ll long long int n,q

股神小L 2016Vijos省选集训 day1

股神小L (stock.c/pas/cpp)============================ 小L厌倦了算法竞赛,希望到股市里一展身手.他凭借自己还行的计算机功底和可以的智商,成功建立一个模型预测了一支股票接下来n天的价格. 我们把这支股票第i天的价格称为a_i.在接下来n天里,每一天小L可以选择花费a_i买入一股或者卖出一股从而获得a_i元收入. 当然小L卖出股票的时候,自己的账户上必须要有至少一股的剩余.现在小L希望知道,在n天过去之后,采取最优策略的情况下自己最多赚到多少钱. 注意

[2016北京集训试题14]股神小D-[LCT]

Description Solution 将(u,v,l,r)换为(1,u,v,l)和(2,u,v,r).进行排序(第4个数为第一关键字,第1个数为第二关键字).用LCT维护联通块的合并和断开.(维护联通块的大小,要维护虚边) 答案统计:每当四元组的第一个数为1(这时候合并点u,v所在连通块,反之拆开),在合并前ans+=size[u]*size[v]即可. Code #include<iostream> #include<cstdio> #include<cstring&g

股神小D [点分治 or LCT]

题面 思路 点分治非常$naive$,不讲了,基本思路就是记录路径最小最大值.....然后没了 重点讲一下LCT的做法(好写不卡常)(点分一堆人被卡到飞起hhhh) 首先,这个路径限制由边限制决定,而树中的每条边都是割边 考虑一条边$i$,范围是$[l_i,r_i]$,那么当时间不在这个范围内的时候,这个边两边的点肯定不能跨过这条边有赚钱路径 那么,也就是说这一条边当且仅当时间在$[l_i,r_i]$范围内的时候生效 这样,我们可以考虑把边权范围限制变成一次加边和一次删边 我们把一条边根据加入删