题目描述
一棵n个点的树,每个点的初始权值为1。对于这棵树有q个操作,每个操作为以下四种操作之一:
+ u v c
:将u到v的路径上的点的权值都加上自然数c;- u1 v1 u2 v2
:将树中原有的边(u1,v1)删除,加入一条新边(u2,v2),保证操作完之后仍然是一棵树;* u v c
:将u到v的路径上的点的权值都乘上自然数c;/ u v
:询问u到v的路径上的点的权值和,求出答案对于51061的余数。
输入输出格式
输入格式:
第一行两个整数n,q
接下来n-1行每行两个正整数u,v,描述这棵树
接下来q行,每行描述一个操作
输出格式:
对于每个/对应的答案输出一行
输入输出样例
说明
10%的数据保证,1<=n,q<=2000
另外15%的数据保证,1<=n,q<=5*10^4,没有-操作,并且初始树为一条链
另外35%的数据保证,1<=n,q<=5*10^4,没有-操作
100%的数据保证,1<=n,q<=10^5,0<=c<=10^4
By (伍一鸣)
一道LCT维护树上信息的题,可以当做加强版模板题了。具体操作对于每一个询问或修改,把一个端点变成根,然后access另一个端点就能分离出两点之间的整条路径组成的一颗Splay,直接在这颗Splay的根上打标记就行了。
#include<cstdio> #include<cctype> #include<algorithm> #define LL long long using namespace std; const int maxn = 1e5 + 5, mod = 51061; char s; int n, m, a, b, c, d, cnt; inline char gc(){ static char buf[2000000], *p1 = buf, *p2 = buf; return (p1 == p2) && (p2 = (p1 = buf) + fread(buf, 1, 2000000, stdin), p1 == p2) ? EOF : *p1++; } inline void read(int & x) { x = 0; static char c = gc(); while(!isdigit(c)) c = gc(); while(isdigit(c)) x = x * 10 + c - '0', c = gc(); } inline void rc(char & x) { x = gc(); while(x != '+' && x != '-' && x != '*' && x != '/') x = gc(); } namespace LCT { const int L = 0, R = 1; struct node { int ch[2], fa, rv, size; LL sum, mul, add, num; }tree[maxn]; #define isrt(x) (tree[tree[x].fa].ch[R] != x && tree[tree[x].fa].ch[L] != x) void init(int n) { for(register int i = 1; i <= n; ++i) tree[i].size = 1, tree[i].mul = 1, tree[i].num = 1, tree[i].sum = 1; } int tl, tr; void push_up(int rt) { tl = tree[rt].ch[L], tr = tree[rt].ch[R]; tree[rt].size = tree[tl].size + tree[tr].size + 1; tree[rt].sum = (tree[tr].sum + tree[tl].sum + tree[rt].num) % mod; } void push_down(int rt) { if(tree[rt].rv) { tree[rt].rv = 0; swap(tree[rt].ch[L], tree[rt].ch[R]); tree[tree[rt].ch[L]].rv ^= 1; tree[tree[rt].ch[R]].rv ^= 1; } if(tree[rt].mul != 1) { tl = tree[rt].ch[L], tr = tree[rt].ch[R]; tree[tl].mul = tree[rt].mul * tree[tl].mul % mod; tree[tr].mul = tree[rt].mul * tree[tr].mul % mod; tree[tl].add = tree[rt].mul * tree[tl].add % mod; tree[tr].add = tree[rt].mul * tree[tr].add % mod; tree[tl].sum = tree[tl].sum * tree[rt].mul % mod; tree[tr].sum = tree[tr].sum * tree[rt].mul % mod; tree[tl].num = tree[tl].num * tree[rt].mul % mod; tree[tr].num = tree[tr].num * tree[rt].mul % mod; tree[rt].mul = 1; } if(tree[rt].add) { tl = tree[rt].ch[L], tr = tree[rt].ch[R]; tree[tl].add = (tree[tl].add + tree[rt].add) % mod; tree[tr].add = (tree[tr].add + tree[rt].add) % mod; tree[tl].sum = (tree[tl].sum + tree[rt].add * tree[tl].size) % mod; tree[tr].sum = (tree[tr].sum + tree[rt].add * tree[tr].size) % mod; tree[tl].num = (tree[tl].num + tree[rt].add) % mod; tree[tr].num = (tree[tr].num + tree[rt].add) % mod; tree[rt].add = 0; } } void rotate(int rt) { int p = tree[rt].fa, a = tree[p].fa; int r = tree[p].ch[R] == rt, l = r ^ 1; if(!isrt(p)) tree[a].ch[tree[a].ch[R] == p] = rt; tree[rt].fa = a, tree[p].fa = rt, tree[tree[rt].ch[l]].fa = p; tree[p].ch[r] = tree[rt].ch[l], tree[rt].ch[l] = p; push_up(p), push_up(rt); } void splay(int rt, int y) { int des = tree[y].fa; while(tree[rt].fa != des) { int p = tree[rt].fa, a = tree[p].fa; push_down(a), push_down(p), push_down(rt); if(p != y) if((tree[a].ch[R] == p) ^ (tree[p].ch[R] == rt)) rotate(rt); else rotate(p); rotate(rt); } } int findrt(int x) {while(!isrt(x))x = tree[x].fa;return x;} void change(const int &x, const int &y) { int u = findrt(x); splay(x, u), push_down(x), tree[x].ch[R] = y; push_up(x); /*!!!!!!注意push_up!!!!!!*/ } int access(int x) { for(change(x, 0); tree[x].fa; x = tree[x].fa) change(tree[x].fa, x); int u = x; while(push_down(x), tree[x].ch[L]) x = tree[x].ch[L]; return splay(x, u), x; } void makeroot(int x) {tree[access(x)].rv ^= 1;} void link(int x, int y) {tree[x = access(x)].rv ^= 1, tree[x].fa = y;} void cut(int x, int y) {change(x, 0), change(y, 0), tree[tree[x].fa == y ? x : y].fa = 0;} bool isconnect(int x, int y) {return access(x) == access(y);} int Qnxt(int x, int type) { x = tree[x].ch[type]; while(tree[x].ch[type ^ 1]) x = tree[x].ch[type ^ 1]; return x; } int GetSum(int x, int y) { makeroot(y);access(x); return tree[findrt(x)].sum; } void add(int x, int y, int dt) { makeroot(y), access(x); int rt = findrt(x); (tree[rt].add += dt) %= mod; (tree[rt].sum += tree[rt].size * dt * 1LL) %= mod; (tree[rt].num += dt) %= mod; } void mul(int x, int y, int dt) { makeroot(y), access(x); int rt = findrt(x); (tree[rt].mul *= dt) %= mod; (tree[rt].add *= dt) %= mod; (tree[rt].sum *= dt) %= mod; (tree[rt].num *= dt) %= mod; } } int main() { read(n), read(m), LCT::init(n); for(register int i = 1; i < n; ++i) { read(a), read(b); LCT::link(a, b); } for(register int i = 1; i <= m; ++i) { rc(s); if(s == '+') read(a), read(b), read(c), LCT::add(a, b, c); else if(s == '-') read(a), read(b), read(c), read(d), LCT::cut(a, b), LCT::link(c, d); else if(s == '/') read(a), read(b), printf("%d\n", LCT::GetSum(a, b)); else if(s == '*') read(a), read(b), read(c), LCT::mul(a, b, c); } return 0; }
没有帐号? 立即注册