P1501 [國家集訓隊]Tree II
阿新 • • 發佈:2019-01-12
自然 isdigit 答案 格式 cte getchar ces 題目 國家集訓隊
\(\color{#0066ff}{ 題目描述 }\)
一棵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的余數。
\(\color{#0066ff}{輸入格式}\)
第一行兩個整數n,q
接下來n-1行每行兩個正整數u,v,描述這棵樹
接下來q行,每行描述一個操作
\(\color{#0066ff}{輸出格式}\)
對於每個/對應的答案輸出一行
\(\color{#0066ff}{輸入樣例}\)
3 2
1 2
2 3
* 1 3 4
/ 1 1
\(\color{#0066ff}{輸出樣例}\)
4
\(\color{#0066ff}{數據範圍與提示}\)
10%的數據保證,\(1\leq n,q\leq 2000\)
另外15%的數據保證,\(1\leq n,q\leq 5*10^4\),沒有-操作,並且初始樹為一條鏈
另外35%的數據保證,\(1\leq n,q\leq 5*10^4\),沒有-操作
100%的數據保證,\(1\leq n,q\leq 10^5,0\leq c\leq 10^4\)
\(\color{#0066ff}{ 題解 }\)
顯然有link,cut的操作
所以用LCT來維護這個樹
對於那些加,乘,類比線段樹打標記來維護
#include<bits/stdc++.h> using namespace std; #define LL long long LL in() { char ch; int x = 0, f = 1; while(!isdigit(ch = getchar()))(ch == '-') && (f = -f); for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48)); return x * f; } const int mod = 51061; const int maxn = 1e5 + 5; struct LCT { protected: struct node { node *ch[2], *fa; LL val, num, add, mul, siz, rev; node(LL val = 1, LL num = 1, LL add = 0, LL mul = 1, LL siz = 1, int rev = 0) : val(val), num(num), add(add), mul(mul), siz(siz), rev(rev) { ch[0] = ch[1] = fa = NULL; } void g(LL a, LL m) { (val *= m) %= mod, (num *= m) %= mod, (add *= m) %= mod, (mul *= m) %= mod; (val += a) %= mod, (num += siz * a % mod) %= mod, (add += a) %= mod; } bool ntr() { return fa && (fa->ch[0] == this || fa->ch[1] == this); } bool isr() { return this == fa->ch[1]; } void trn() { std::swap(ch[0], ch[1]), rev ^= 1; } void dwn() { if(rev) { if(ch[0]) ch[0]->trn(); if(ch[1]) ch[1]->trn(); rev = 0; } if(ch[0]) ch[0]->g(add, mul); if(ch[1]) ch[1]->g(add, mul); add = 0, mul = 1; } void upd() { siz = 1, num = val; if(ch[0]) siz += ch[0]->siz, num += ch[0]->num; if(ch[1]) siz += ch[1]->siz, num += ch[1]->num; } }s[maxn], *t[maxn]; int top; void rot(node *x) { node *y = x->fa, *z = y->fa; int k = x->isr(); node *w = x->ch[!k]; if(y->ntr()) z->ch[y->isr()] = x; x->ch[!k] = y, y->ch[k] = w; y->fa = x, x->fa = z; if(w) w->fa = y; y->upd(), x->upd(); } void splay(node *o) { t[top = 1] = o; while(t[top]->ntr()) t[top + 1] = t[top]->fa, top++; while(top) t[top--]->dwn(); while(o->ntr()) { if(o->fa->ntr()) rot(o->isr() ^ o->fa->isr()? o : o->fa); rot(o); } } void access(node *x) { for(node *y = NULL; x; x = (y = x)->fa) splay(x), x->ch[1] = y, x->upd(); } void makeroot(node *x) { access(x), splay(x), x->trn(); } node *findroot(node *x) { access(x), splay(x); while(x->dwn(), x->ch[0]) x = x->ch[0]; return splay(x), x; } void link(node *x, node *y) { if(findroot(x) == findroot(y)) return; makeroot(x), x->fa = y; } void cut(node *x, node *y) { makeroot(x), access(y), splay(y); if(y->ch[0] == x) y->ch[0] = x->fa = NULL; } int query(node *x, node *y) { makeroot(x), access(y), splay(y); return y->num % mod; } void addpath(node *x, node *y, LL c) { makeroot(x), access(y), splay(y); y->g(c, 1); } void mulpath(node *x, node *y, LL c) { makeroot(x), access(y), splay(y); y->g(0, c); } public: void link(int x, int y) { link(s + x, s + y); } void cut(int x, int y) { cut(s + x, s + y); } void add(int x, int y, LL c) { addpath(s + x, s + y, c); } void mul(int x, int y, LL c) { mulpath(s + x, s + y, c); } int query(int x, int y) { return query(s + x, s + y); } }v; char getch() { char ch = getchar(); while(ch != '+' && ch != '-' && ch != '*' && ch != '/') ch = getchar(); return ch; } int main() { int n = in(), q = in(); for(int i = 1; i < n; i++) v.link(in(), in()); int a, b, c, d; while(q --> 0) { char ch = getch(); if(ch == '+') a = in(), b = in(), c = in(), v.add(a, b, c); if(ch == '-') a = in(), b = in(), c = in(), d = in(), v.cut(a, b), v.link(c, d); if(ch == '*') a = in(), b = in(), c = in(), v.mul(a, b, c); if(ch == '/') a = in(), b = in(), printf("%d\n", v.query(a, b)); } return 0; }
P1501 [國家集訓隊]Tree II