• 树剖模板


    题目描述

    如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:

    操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z

    操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和

    操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z

    操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和

    输入输出格式

    输入格式:

    第一行包含4个正整数N、M、R、P,分别表示树的结点个数、操作个数、根节点序号和取模数(即所有的输出结果均对此取模)。

    接下来一行包含N个非负整数,分别依次表示各个节点上初始的数值。

    接下来N-1行每行包含两个整数x、y,表示点x和点y之间连有一条边(保证无环且连通)

    接下来M行每行包含若干个正整数,每行表示一个操作,格式如下:

    操作1: 1 x y z

    操作2: 2 x y

    操作3: 3 x z

    操作4: 4 x

    
    输出格式:

    输出包含若干行,分别依次表示每个操作2或操作4所得的结果(对P取模)

    输入输出样例

    输入样例#1:
    5 5 2 24
    7 3 7 8 0 
    1 2
    1 5
    3 1
    4 1
    3 4 2
    3 2 2
    4 5
    1 5 1 3
    2 1 3
    输出样例#1:
    2
    21

    说明

    时空限制:1s,128M

    数据规模:

    对于30%的数据:N<=10,M<=10

    对于70%的数据:N<=1000,M<=1000

    对于100%的数据:N<=100000,M<=100000

    (其实,纯随机生成的树LCA+暴力是能过的,可是,你觉得可能是纯随机的么233)



    #include<cstdio>
    #include<cctype> #include<cstring> #include<algorithm> using namespace std; inline int read() { int x = 0, flag = 1; char c; while(! isgraph(c = getchar())) if(c == '-') flag *= - 1; while(isgraph(c)) x = x * 10 + c - '0', c = getchar(); return x * flag; } const int MAXN = (int)1e5 + (1 << 5); int w[MAXN]; int top; struct edge { int v, next; }G[MAXN << 1]; int head[MAXN]; int n, m, root, MOD; void add_edge(int u, int v) { G[top].v = v; G[top].next = head[u]; head[u] = top ++; } struct node { int w, dep, fa, son, size, top, ID, last; }a[MAXN]; void DFS1(int u, int fa) { a[u].dep = a[fa].dep + 1; a[u].fa = fa; a[u].size = 1; a[u].son = - 1; for(int i = head[u]; i != - 1; i = G[i].next) { int v = G[i].v; if(v == fa) continue; DFS1(v, u); a[u].size += a[v].size; if(a[u].son == - 1 || a[v].size > a[a[u].size].size) a[u].son = v; } } int cnt; void DFS2(int u, int top) { a[u].top = top; a[u].ID = ++ cnt; if(a[u].son == - 1) { a[u].last = a[u].ID; return; } DFS2(a[u].son, top); for(int i = head[u]; i != - 1; i = G[i].next) if(G[i].v != a[u].son && G[i].v != a[u].fa) DFS2(G[i].v, G[i].v); a[u].last = cnt; } struct segmenttree { int sum, tag; }T[MAXN << 2]; void modify(int u, int curL, int curR, int L, int R, int delta) { if(curL >= L && curR <= R) { T[u].tag += delta; T[u].sum += delta * (curR - curL + 1); return; } int mid = (curL + curR) >> 1; if(L <= mid) modify(u << 1, curL, mid, L, R, delta); if(R > mid) modify((u << 1) + 1, mid + 1, curR, L, R, delta); T[u].sum += (min(curR, R) - max(curL, L) + 1) * delta; } void update(int u, int v, int delta) { while(a[u].top != a[v].top) { if(a[a[u].top].dep < a[a[v].top].dep) swap(u, v); modify(1, 1, n, a[a[u].top].ID, a[u].ID, delta); u = a[a[u].top].fa; } if(a[u].ID < a[v].ID) modify(1, 1, n, a[u].ID, a[v].ID, delta); else modify(1, 1, n, a[v].ID, a[u].ID, delta); } int query(int u, int curL, int curR, int L, int R) { if(curL >= L && curR <= R) return T[u].sum; int mid = (curL + curR) >> 1, ret = 0; if(L <= mid) ret += query(u << 1, curL, mid, L, R); if(R > mid) ret += query((u << 1) + 1, mid + 1, curR, L, R); ret += (min(curR, R) - max(curL, L) + 1) * T[u].tag; return ret; } int ask(int u, int v) { int ret = 0; while(a[u].top != a[v].top) { if(a[a[u].top].dep < a[a[v].top].dep) swap(u, v); ret += query(1, 1, n, a[a[u].top].ID, a[u].ID); u = a[a[u].top].fa; } if(a[u].ID < a[v].ID) ret += query(1, 1, n, a[u].ID, a[v].ID); else ret += query(1, 1, n, a[v].ID, a[u].ID); return ret; } void print(int x) { if(x < 0) putchar('-'); if(x == 0) putchar('0'); int top = 0, ans[36]; while(x) ans[top ++] = x % 10, x /= 10; for(; top; top --) putchar(ans[top - 1] + '0'); } int main() { #ifndef ONLINE_JUDGE freopen("L3384.in", "r", stdin); freopen("L3384.out", "w", stdout); #endif n = read(), m = read(), root = read(), MOD = read(); for(int i = 1; i <= n; i ++) a[i].w = read(); top = 0; memset(head, - 1, sizeof(head)); for(int i = 1; i < n; i ++) { int u = read(), v = read(); add_edge(u, v); add_edge(v, u); } a[root].dep = - 1; DFS1(root, root); cnt = 0; DFS2(root, root); memset(T, 0, sizeof(T)); for(int i = 1; i <= n; i ++) modify(1, 1, n, a[i].ID, a[i].ID, a[i].w); for(int i = 0; i < m; i ++) { int opt = read(); switch (opt) { case 1: { int u = read(), v = read(), delta = read(); update(u, v, delta); break; } case 2: { int u = read(), v = read(); print(ask(u, v) % MOD); putchar(' '); break; } case 3: { int u = read(), delta = read(); modify(1, 1, n, a[u].ID, a[u].last, delta); break; } case 4: { int u = read(); print(query(1, 1, n, a[u].ID, a[u].last) % MOD); putchar(' '); break; } } } }
  • 相关阅读:
    兼容火狐几秒后跳转页面
    js 利用sina ip库获取ip及通信服务商
    jQuery.validate 中文API
    s:select标签的Map形式使用
    【原创随笔】reCAPTCHA加密验证Email地址,正确才可完整查看地址!
    eclipse编辑jsp文件和javascript代码很卡解决办法
    oracle 10 R2 静默安装 + psu
    【容易成功的十种能力你具备几种
    CentOS 新虚拟机网卡设置
    【与人沟通的技巧很重要】
  • 原文地址:https://www.cnblogs.com/ZeonfaiHo/p/6402839.html
Copyright © 2020-2023  润新知