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


    树链剖分+可持久化线段树....这个一眼可以看出来, 因为可持久化所以写了标记永久化(否则就是区间修改的线段树的持久化..不会), 结果就写挂了, T得飞起...和管理员拿数据调后才发现= = 做法:码码码码码码码码...码完就AC啦. O(M log N)

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

    #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;
    AddEdge(u, v), AddEdge(v, u);
    }
    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 ", 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

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

    Sample Input

    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

    Sample Output

    12
    7
    7

    HINT



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

    Source

  • 相关阅读:
    Java基础 Day02(个人复习整理)
    Java基础 Day01(个人复习整理)
    linux-rpm
    linux常用命令
    rpm构建流程学习总结
    git相关
    sql相关
    ssh打通
    element ui FORM表单
    python threading多线程
  • 原文地址:https://www.cnblogs.com/JSZX11556/p/5185345.html
Copyright © 2020-2023  润新知