• P1501 [国家集训队]Tree II


    (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%的数据保证,(1leq n,qleq 2000)

    另外15%的数据保证,(1leq n,qleq 5*10^4),没有-操作,并且初始树为一条链

    另外35%的数据保证,(1leq n,qleq 5*10^4),没有-操作

    100%的数据保证,(1leq n,qleq 10^5,0leq cleq 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
    ", v.query(a, b));
    	}
    	return 0;
    }
    
  • 相关阅读:
    HDU5792 World is Exploding(树状数组)
    POJ3415 Common Substrings(后缀数组 单调栈)
    POJ2406 Power Strings(KMP,后缀数组)
    HDU5489 Removed Interval(动态规划)
    HDU1899 Sum the K-th's(树状数组)
    Codeforces Round #363 Fix a Tree(树 拓扑排序)
    数组-07. 求一批整数中出现最多的个位数字
    数组-06. 找出不是两个数组共有的元素
    数组-05. 字符串字母大小写转换
    数组-04. 查找整数
  • 原文地址:https://www.cnblogs.com/olinr/p/10260276.html
Copyright © 2020-2023  润新知