# BZOJ 3221: [Codechef FEB13] Obserbing the tree树上询问( 可持久化线段树 + 树链剖分 )

-------------------------------------------------------------------

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;

typedef long long ll;

const int maxn = 100009;

int N, Q, Top, L, R, dfn, T;
int Id[maxn], sz[maxn], dep[maxn], fa[maxn], ch[maxn], top[maxn];

inline int getint() {
char c = getchar();
for(; !isdigit(c); c = getchar());
int ret = 0;
for(; isdigit(c); c = getchar()) ret = ret * 10 + c - '0';
return ret;
}
inline ll getll() {
char c = getchar();
for(; !isdigit(c); c = getchar());
ll ret = 0;
for(; isdigit(c); c = getchar()) ret = ret * 10 + c - '0';
return ret;
}

struct edge {
int t;
edge* n;
} E[maxn << 1], *Pt = E, *H[maxn];

inline void AddEdge(int u, int v) {
Pt->t = v, Pt->n = H[u], H[u] = Pt++;
}

void dfs(int x) {
sz[x] = 1, ch[x] = -1;
for(edge* e = H[x]; e; e = e->n) if(e->t != fa[x]) {
dep[e->t] = dep[x] + 1;
fa[e->t] = x;
dfs(e->t);
sz[x] += sz[e->t];
if(!~ch[x] || sz[ch[x]] < sz[e->t]) ch[x] = e->t;
}
}

void DFS(int x) {
top[x] = Top;
Id[x] = ++dfn;
if(~ch[x]) DFS(ch[x]);
for(edge* e = H[x]; e; e = e->n)
if(e->t != fa[x] && e->t != ch[x]) DFS(Top = e->t);
}

void Init() {
N = getint(), Q =getint();
for(int i = 1; i < N; i++) {
int u = getint() - 1, v = getint() - 1;
}
fa[0] = -1, dep[0] = 0, dfs(0);
DFS(dfn = Top = 0);
}

struct Mark {
ll f, d;
Mark() : f(0), d(0) {
}
Mark(ll _f, ll _d) : f(_f), d(_d) {
}
Mark operator += (const Mark o) {
f += o.f, d += o.d;
return *this;
}
Mark Rev(int len) {
return Mark(f + (len - 1) * d, -d);
}
Mark Cut(int len) {
return Mark(f + len * d, d);
}
inline ll Sum(int len, int s = 0) {
return ll(len) * (f + d * s) + (d * len * (len - 1) >> 1);
}
};

struct Node {
Node *lc, *rc;
ll sm;
Mark t;
inline void upd(int len) {
if(len > 1) {
sm = lc->sm + rc->sm;
} else
sm = 0;
sm += t.Sum(len);
}
} pool[20000009], *pt, *Root[maxn];

void Init_sgt() {
pt = pool;
pt->lc = pt->rc = pt;
pt->t = Mark();
Root[0] = pt++;
}

int LCA(int u, int v) {
for(; top[u] != top[v]; u = fa[top[u]])
if(dep[top[u]] < dep[top[v]]) swap(u, v);
return dep[u] < dep[v] ? u : v;
}

Node* Modify(Node* t, int l, int r, Mark mk) {
Node* o = pt++;
o->t = t->t;
o->lc = t->lc, o->rc = t->rc;
if(L <= l && r <= R) {
o->t += mk;
} else {
int m = (l + r) >> 1;
if(L <= m) o->lc = Modify(o->lc, l, m, mk);
if(m < R) o->rc = Modify(o->rc, m + 1, r, L <= m ? mk.Cut(m - max(L, l) + 1) : mk);
}
o->upd(r - l + 1);
return o;
}

Node* MODIFY(Node* p, int u, int v, Mark t) {
int lca = LCA(u, v);
for(; top[u] != top[v]; u =fa[top[u]]) {
if(dep[top[u]] < dep[top[v]]) {
t = t.Rev(dep[u] + dep[v] - (dep[lca] << 1) + 1);
swap(u, v);
}
L = Id[top[u]], R = Id[u];
p = Modify(p, 1, N, t.Rev(dep[u] - dep[top[u]] + 1));
t = t.Cut(dep[u] - dep[top[u]] + 1);
}
if(dep[u] > dep[v]) {
t = t.Rev(dep[u] - dep[v] + 1);
swap(u, v);
}
L = Id[u], R = Id[v];
p = Modify(p, 1, N, t);
return p;
}

void Query(Node* t, int l, int r, Mark o, ll &ret) {
if(L <= l && r <= R) {
ret += t->sm + o.Sum(r - l + 1);
} else {
int m = (l + r) >> 1;
o += t->t;
if(L <= m) Query(t->lc, l, m, o, ret);
if(m < R) Query(t->rc, m + 1, r, o.Cut(m + 1 - l), ret);
}
}

ll QUERY(Node* t, int u, int v) {
ll ret = 0;
for(; top[u] != top[v]; u = fa[top[u]]) {
if(dep[top[u]] < dep[top[v]]) swap(u, v);
L = Id[top[u]], R = Id[u];
Query(t, 1, N, Mark(), ret);
}
if(dep[u] > dep[v]) swap(u, v);
L = Id[u], R = Id[v];
Query(t, 1, N, Mark(), ret);
return ret;
}

void Work() {
char c;
int t = 0;
ll ans = 0;
Init_sgt();
Node* Rt = Root[0];
while(Q--) {
scanf(" %c", &c);
if(c == 'c') {
int u = getll() ^ ans, v = getll() ^ ans;
ll f = getll(), d =getll();
Rt = Root[++t] = MODIFY(Rt, u - 1, v - 1, Mark(f, d));
} else if(c == 'q') {
printf("%lld\n", ans = QUERY(Rt, (getll() ^ ans) - 1, (getll() ^ ans) - 1));
} else
Rt = Root[getll() ^ ans];
}
}

int main() {
Init();
Work();
return 0;
}

-------------------------------------------------------------------

## 3221: [Codechef FEB13] Obserbing the tree树上询问

Time Limit: 20 Sec  Memory Limit: 1280 MB
Submit: 295  Solved: 55
[Submit][Status][Discuss]

## Description

小N最近在做关于树的题。今天她想了这样一道题，给定一棵N个节点的树，节点按1~N编号，一开始每个节点上的权值都是0，接下来有M个操作。第一种操作是修改，给出4个整数X,Y,A,B,对于X到Y路径上加上一个首项是A，公差是B的等差数列，因为小N十分谨慎，所以她每做完一个修改操作就会保存一次，初始状态是第0次保存的局面。第二种操作是求和，给出2个整数X,Y，输出X到Y路径上所有节点的权值和。第三种操作是读取之前第X次保存的局面，所有节点的状态回到之前第X次保存的状态。现在请你对每一个求和操作输出答案。

## Input

第一行2个整数N,M表示节点个数和操作次数。
接下来N-1行每行2个整数Ui,Vi表示了这棵树中Ui和Vi这2个节点间有边相连。
接下来M行每行先有一个字符表示了操作的类型：
如果是’c’，那么代表了一个修改操作，接下来有4个整数X1,Y1,A,B，为了使得询问在线，正确的X=X1 xor上次输出的数,Y=Y1 xor上次输出的数,如果之前没有输出过那么当成0。
如果是’q’，那么代表了一个求和操作，接下来有2个整数X1,Y1,和修改操作一样需要xor上次输出。
如果是’l’，那么代表了一次读取操作，接下来1个整数X1，正确的X=X1 xor上次输出的数。

## Output

对于每一个求和操作，输出求和后的值。

5 7
1 2
2 3
3 4
4 5
c 2 5 2 3
c 3 4 5 10
q 1 3
l 13
q 13 15
l 6
q 6 4

12
7
7

## HINT

100%的数据中N,M<=100000,0<=A,B<=1000,0<=X1,Y1<=10^1,修改次数<M/2，不会读取没保存的局面

## Source

posted @ 2016-02-08 23:32  JSZX11556  阅读(391)  评论(0编辑  收藏