[XSY 1019] 小A学树论 Splay维护入栈出栈序

题意

  给定一棵 n 个节点的树. 这棵树以 1 为根, 每个点有点权.

  在树上支持三种操作:

    ① 查询以 x 为根的子树的点权之和;

    ② 将以 x 为根的子树中的每个点的点权增加 w ;

    ③ 将 以 x 为根的子树转移到 y 的直接后继.

  $n \le 100000$ .

实现

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <cstdlib>
  4 #include <cctype>
  5 #include <vector>
  6 using namespace std;
  7 #define F(i, a, b) for (register int i = (a); i <= (b); i++)
  8 #define LL long long
  9 namespace Input {
 10     const int S = 2000000;
 11     char s[S], *h = s+S, *t = h;
 12     inline char getchr(void) { if (h == t) fread(s, 1, S, stdin), h = s; return *h++; }
 13     inline LL rd(void) {
 14         LL f = 1; char c = getchr(); for (; !isdigit(c); c = getchr()) if (c == ‘-‘) f = -1;
 15         LL x = 0; for (; isdigit(c); c = getchr()) x = x*10+c-‘0‘; return x*f;
 16     }
 17 }
 18 using Input::rd;
 19
 20 const int N = 200005;
 21
 22 int n, m; LL w[N];
 23 vector<int> g[N];
 24 inline void Init(int x, int y) { g[x].push_back(y), g[y].push_back(x); }
 25
 26 int tot, In[N], Out[N], List[N];
 27 inline void Add(int x, int sign) { List[++tot] = x, (sign == +1 ? In[x] = tot : Out[x] = tot); }
 28 inline void Prework(int x, int fa) {
 29     Add(x, +1);
 30     for (vector<int>::iterator it = g[x].begin(); it != g[x].end(); it++)
 31         if (*it != fa) Prework(*it, x);
 32     Add(x, -1);
 33 }
 34
 35 #define LC (c[x][0])
 36 #define RC (c[x][1])
 37
 38 int rt, c[N][2], par[N], siz[N];
 39 LL key[N], sum[N], tag[N];
 40
 41 inline void Trav(int x) { if (!x) return; Trav(LC), printf("%d ", List[x]), Trav(RC); }
 42 void Put(int x) { Trav(x), puts(""); }
 43
 44 inline void Up(int x) { siz[x] = siz[LC] + siz[RC] + 1, sum[x] = sum[LC] + sum[RC] + key[x]; }
 45 inline void Down(int x, LL tmp) { key[x] += tmp, sum[x] += siz[x] * tmp, tag[x] += tmp; }
 46 inline void Clear(int x) { if (!tag[x]) return; Down(LC, tag[x]), Down(RC, tag[x]), tag[x] = 0; }
 47
 48 inline void Rot(int x) {
 49     int t = par[x], L = (c[t][1] == x), R = L^1;
 50
 51     if (par[t] > 0)
 52         c[par[t]][c[par[t]][1] == t] = x;
 53     par[x] = par[t];
 54
 55     if (c[x][R] > 0)
 56         par[c[x][R]] = t;
 57     c[t][L] = c[x][R];
 58
 59     c[x][R] = t, par[t] = x;
 60     Up(t), Up(x);
 61 }
 62 inline void Splay(int x, int f = 0){
 63     static int L[N]; int tot = 0;
 64     L[++tot] = x;
 65     for (int i = x; par[i] != f; i = par[i]) L[++tot] = par[i];
 66     for (; tot > 0; L[tot--] = 0)
 67         Clear(L[tot]);
 68
 69     for (; par[x] != f; Rot(x)) {
 70         int y = par[x], z = par[y];
 71         if (z != f && par[z] != f)
 72             (c[z][0] == y) ^ (c[y][0] == x) ? Rot(x) : Rot(y);
 73     }
 74     if (!f) rt = x;
 75 }
 76
 77 void Build(int &x, int L, int R) {
 78     x = (L+R)>>1;
 79     key[x] = w[List[x]], siz[x] = 1;
 80     if (L < x) Build(LC, L, x-1), par[LC] = x;
 81     if (x < R) Build(RC, x+1, R), par[RC] = x;
 82     Up(x);
 83 }
 84
 85 inline int Pre(int x) {
 86     Splay(x);
 87     int y = LC;
 88     while (c[y][1] > 0) y = c[y][1];
 89     Splay(y);
 90     return y;
 91 }
 92 inline int Nxt(int x) {
 93     Splay(x);
 94     int y = RC;
 95     while (c[y][0] > 0) y = c[y][0];
 96     Splay(y);
 97     return y;
 98 }
 99
100 inline LL Sum(int x) {
101     int L = Pre(In[x]);
102     int R = Nxt(Out[x]);
103     Splay(L);
104     Splay(R, rt);
105     return sum[c[R][0]] >> 1;
106 }
107 inline void Addsub(int x, LL y) {
108     int L = Pre(In[x]);
109     int R = Nxt(Out[x]);
110     Splay(L);
111     Splay(R, rt);
112     Down(c[R][0], y);
113     Up(R), Up(rt);
114 }
115 inline void Linkcut(int x, int y) {
116     int L = Pre(In[x]);
117     int R = Nxt(Out[x]);
118     Splay(L);
119     Splay(R, rt);
120
121     int now = c[R][0];
122     par[now] = c[R][0] = 0, Up(R), Up(L);
123
124     L = In[y], R = Nxt(In[y]);
125     Splay(L);
126     Splay(R, rt);
127
128     c[R][0] = now, par[now] = R, Up(R), Up(L);
129 }
130
131 int main(void) {
132     #ifndef ONLINE_JUDGE
133         freopen("xsy1019.in", "r", stdin);
134         //  freopen("xsy1019.out", "w", stdout);
135     #endif
136
137     n = rd(), m = rd();
138     F(i, 1, n) w[i] = rd();
139     F(i, 1, n-1) {
140         int x = rd(), y = rd();
141         Init(x, y);
142     }
143
144     Add(0, +1);
145     Prework(1, -1);
146     Add(0, -1);
147
148     tot = 0;
149     Build(rt, 1, 2*n+2);
150
151     F(i, 1, m) {
152         int k = rd();
153         if (k == 1) {
154             int x = rd();
155             printf("%lld\n", Sum(x));
156         }
157         else if (k == 2) {
158             int x = rd(); LL y = rd();
159             Addsub(x, y);
160         }
161         else {
162             int x = rd(), y = rd();
163             Linkcut(x, y);
164         }
165     }
166
167     return 0;
168 }
时间: 2024-10-09 18:46:26

[XSY 1019] 小A学树论 Splay维护入栈出栈序的相关文章

BZOJ 3786 星系探索 Splay维护树的入栈出栈序

题目大意:给出一棵树,要求有以下这些操作:1.求出一个节点到根的点权和.2.将一个节点的父亲改变.3.将一个子树中的每一个节点都加上一个权值. 思路:LCT就不用想了,因为有子树操作.然后就是一个很神奇的东西了,就是Splay维护树的入栈出栈序.这个玩应是做了这个题之后才知道的.但是感觉真的很dio. 首先,我们先按照题意,将树建出来.然后从根开始深搜,这样一个点进入DFS函数和出DFS函数的时候就会有两个时间点,就是入栈的时间和出栈的时间.然后利用Splay维护一个序列,就是入栈出栈的顺序.在

[xsy1019]小A学树论

题意:维护一棵带点权的树,支持查询子树权值和,子树整体增值,换父亲 复习splay 刚开始做的时候智障了,这道题其实直接用splay维护出栈入栈序列就好了 #include<stdio.h> struct edge{ int to,nex; }e[200010]; #define ll long long int fa[200010],ch[200010][2],siz[200010],nv[100010],h[100010],in[100010],out[100010],M,rt,tot;

[BZOJ 3786] 星系探索 Splay维护入栈出栈序

题意 给定一棵 n 个节点, 点有点权, 以 1 为根的有根树. m 次操作: ① 查询点 d 到根的点权之和. ② 将 x 及其子树截出来, 作为 y 的儿子. ③ 将以 p 为根的子树的点权增加 q . $n \le 100000$ . 实现 1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cctype> 5 #include <vector>

poj3468 线段树 or splay

poj3468  裸线段树.因为在熟悉splay 所以就用splay交了一发...开始用的scanf()!==2 居然TLE了...然后我就当单组测试数据做的 然后就过了  囧TZ #include <iostream> #include <cstdio> #include <cstdlib> #include <algorithm> #include <cstring> #include <cmath> using namespac

刷题总结——二逼平衡树(bzoj3224线段树套splay)

题目: Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为大于x,且最小的数) Input 第一行两个数 n,m 表示长度为n的有序序列和m个操作第二行有n个数,表示有序序列下面有m行,opt表示操作标号若opt=1 则为操作1,之后有三个数l,r,k 表示查询k在区间[l,r

LCA(倍增在线算法) codevs 2370 小机房的树

codevs 2370 小机房的树 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子,他们不想花费太多精力.已知从某个节点爬到其父亲节点要花费 c 的能量(从父亲节点爬到此节点也相同),他们想找出一条花费精力最短的路,以使得搞基的时候精力旺盛,他们找到你要你设计

小故事学设计模式之Decorate: (二)老婆的新衣服

老婆有一件蓝色的裙子和一件粉色的裙子, 不管怎么穿,她还是原来的老婆. 但是在软件里就不一定了, 如果把老婆比作一个class的话, 有一种做法是会因为增加了两个新的Property而继承出两个子类: "穿裙子的老婆, 穿粉色上衣的老婆". 你这样弄出两个子类也没什么不对, 问题是当MM的有上百件服装的时候,就会产生上百个子类,这个不好,将来万一父类一变化,下面上百个子类都要一个个地去修改,太乱了. 有一个更合理的方式来解决这个"老婆的装饰问题".我们的要求是:  

积累的VC编程小技巧之树操作

1.如何在TreeList中加图标? [问题提出]  请问treeview控件和treectrl控件的用法有何不同呢?向如何imagelist控件中加图象呀?  [解决方法]  1)    HICON hicon[8];    m_imageList.Create(16,16,0,8,8);    hicon[0]=AfxGetApp()->LoadIcon(IDI_ICON0);    hicon[1]=AfxGetApp()->LoadIcon(IDI_ICON1);    hicon[2

codevs 2370 小机房的树

2370 小机房的树 时间限制: 1 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题目描述 Description 小机房有棵焕狗种的树,树上有N个节点,节点标号为0到N-1,有两只虫子名叫飘狗和大吉狗,分居在两个不同的节点上.有一天,他们想爬到一个节点上去搞基,但是作为两只虫子,他们不想花费太多精力.已知从某个节点爬到其父亲节点要花费 c 的能量(从父亲节点爬到此节点也相同),他们想找出一条花费精力最短的路,以使得搞基的时候精力旺盛,他们找到你要你设计一个程序来找到