2018 焦作网络预赛 E: Jiu Yuan Wants to Eat 树链剖分

题目链接:https://nanti.jisuanke.com/t/A2015

题意:一个树,4中操作,分别是两点间路径的,乘、加、异或、和

题解:对应乘和加,就很简单了,两个laz标记,对于加的直接更新,对于乘的,还要把加的laz也要乘上,那么就是异或了,刚开始没有注意到模数,一直在想分开对于某一位进行标记,但是这个的膜是2^64,那么也就是总共的64位了,这里也要用ull,         因为二进制中 : - x = !x + 1 所以 !x = - x - 1,因为这里用的都是正数ull,溢出的也就相当于膜了,所以直接算就好,这个题原本的时限是3s,但是中石油设的是2s,优化了1个小时也算是过了。。。。

2162ms:

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
 
const int N = 1e5 + 10;
 
struct edge{
    int to, nex;
}e[N * 2];
int n, q;
int head[N], len;
int in[N], son[N], num[N], deep[N], fa[N], pre[N], tot; 
 
void init() {
    for(int i = 1; i <= n; i++) {
        head[i] = -1;
    }
    len = 0;
    tot = 0;
}
void add(int x, int y) {
    e[len].to = y;
    e[len].nex = head[x];
    head[x] = len++;
}
 
void dfs1(int u) {
    son[u] = -1;
    num[u] = 1;
    int to;
    for(int i = head[u]; i != -1; i = e[i].nex) {
        to = e[i].to;
        if(to == fa[u]) continue;
        deep[to] = deep[u] + 1;
        fa[to] = u;
        dfs1(to);
         
        num[u] += num[to];
        if(son[u] == -1 || num[to] > num[son[u]]) {
            son[u] = to;
        }
    }
}
void dfs2(int u, int rt) {
    in[u] = ++tot;
    pre[u] = rt;
    if(son[u] != -1) {
        dfs2(son[u], rt);
    } 
    int to;
    for(int i = head[u]; i != -1; i = e[i].nex) {
        to = e[i].to;
        if(to == fa[u] || to == son[u]) continue;
        dfs2(to, to);
    }
}
struct node {
    int l, r, len;
    ll laz1, laz2;
    ll sum;
}tree[N << 2];
void build(int l, int r, int cur) {
    tree[cur].l = l;
    tree[cur].r = r;
    tree[cur].len = r - l + 1;
    tree[cur].laz1 = 1;
    tree[cur].laz2 = 0;
    tree[cur].sum = 0;
    if(l == r) return;
    int mid = (r + l) >> 1;
    build(l, mid, cur << 1);
    build(mid + 1, r, cur << 1 | 1);
}
void pushdown(int cur) {
    if(tree[cur].laz1 != 1) {
        tree[cur << 1].laz1 *= tree[cur].laz1;
        tree[cur << 1].laz2 *= tree[cur].laz1;
        tree[cur << 1].sum *= tree[cur].laz1;
        tree[cur << 1 | 1].laz1 *= tree[cur].laz1;
        tree[cur << 1 | 1].laz2 *= tree[cur].laz1;
        tree[cur << 1 | 1].sum *= tree[cur].laz1;
        tree[cur].laz1 = 1;
    }
    if(tree[cur].laz2 != 0) {
        tree[cur << 1].laz2 += tree[cur].laz2;
        tree[cur << 1].sum += tree[cur << 1].len * tree[cur].laz2;
        tree[cur << 1 | 1].laz2 += tree[cur].laz2;
        tree[cur << 1 | 1].sum += tree[cur << 1 | 1].len * tree[cur].laz2;
        tree[cur].laz2 = 0;
    }
}
void pushup(int cur) {
    tree[cur].sum = tree[cur << 1].sum + tree[cur << 1 | 1].sum;
}
void update(int pl, int pr, int cur, ll val, int op) {
    if(pl <= tree[cur].l && tree[cur].r <= pr) {
        if(op == 1) {
            tree[cur].sum *= val;
            tree[cur].laz1 *= val;
            tree[cur].laz2 *= val;
        } else {
            tree[cur].sum += tree[cur].len * val;
            tree[cur].laz2 += val;
        }
        return;
    }
    pushdown(cur);
    if(pl <= tree[cur << 1].r) update(pl, pr, cur << 1, val, op);
    if(pr >= tree[cur << 1 | 1].l) update(pl, pr, cur << 1 | 1, val, op);
    pushup(cur);
}
void solve (int x, int y, ll val, int op) {
    int fx = pre[x], fy = pre[y];
    while(fx != fy) {
        if(deep[fx] < deep[fy]) {
            swap(x, y);
            swap(fx, fy);
        }
        update(in[fx], in[x], 1, val, op);
        x = fa[fx];
        fx = pre[x];
    }
    if(deep[x] > deep[y]) swap(x, y);
    update(in[x], in[y], 1, val, op);
}
ll query(int pl, int pr, int cur) {
    if(pl <= tree[cur].l && tree[cur].r <= pr) {
        return tree[cur].sum;
    }
    ll res = 0;
    pushdown(cur);
    if(pl <= tree[cur << 1].r) res += query(pl, pr, cur << 1);
    if(pr >= tree[cur << 1 | 1].l) res += query(pl, pr, cur << 1 | 1);
    return res;
}
 
ll solvequery(int x, int y) {
    int fx = pre[x], fy = pre[y];
    ll res = 0;
    while(fx != fy) {
        if(deep[fx] < deep[fy]) {
            swap(x, y);
            swap(fx, fy);
        }
        res += query(in[fx], in[x], 1);
        x = fa[fx];
        fx = pre[x];
    }
    if(deep[x] > deep[y]) swap(x, y);
    res += query(in[x], in[y], 1);
    return res;
}
int main() {
    int y;
    int op, u, v;
    ll x ;
    deep[1] = 1;
    fa[1] = 0;
    while(~scanf("%d", &n)) {
        init();
        for(int i = 2; i <= n; i++) {
            scanf("%d", &y);
            add(y, i);
            add(i, y);
        }
         
        dfs1(1);
         
        dfs2(1, 1);
        build(1, n, 1);
        scanf("%d", &q);
        while(q--) {
            scanf("%d %d %d", &op, &u, &v);
            if(op == 1) {
                scanf("%llu", &x);
                solve(u, v, x, 1);
            } else if(op == 2) {
                scanf("%llu", &x);
                solve(u, v, x, 2);
            } else if(op == 3) {
                solve(u, v, -1, 1);
                solve(u, v, -1, 2); 
            } else {
                printf("%llu\n", solvequery(u, v));
            }
        }
    }
    return 0;
}

1990ms:

#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
const int N = 1e5 + 1;
struct edge{
    int to, nex;
}e[N * 2];
int n, q;
int head[N], len;
int in[N], son[N], num[N], deep[N], fa[N], pre[N], tot; 
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
  
void init() {
    for(int i = 1; i <= n; i++) {
        head[i] = -1;
    }
    len = 0;
    tot = 0;
}
void add(int x, int y) {
    e[len].to = y;
    e[len].nex = head[x];
    head[x] = len++;
}
  
void dfs1(int u) {
    son[u] = -1;
    num[u] = 1;
    int to;
    for(int i = head[u]; i != -1; i = e[i].nex) {
        to = e[i].to;
        if(to == fa[u]) continue;
        deep[to] = deep[u] + 1;
        fa[to] = u;
        dfs1(to);
          
        num[u] += num[to];
        if(son[u] == -1 || num[to] > num[son[u]]) {
            son[u] = to;
        }
    }
}
void dfs2(int u, int rt) {
    in[u] = ++tot;
    pre[u] = rt;
    if(son[u] != -1) {
        dfs2(son[u], rt);
    } 
    int to;
    for(int i = head[u]; i != -1; i = e[i].nex) {
        to = e[i].to;
        if(to == fa[u] || to == son[u]) continue;
        dfs2(to, to);
    }
}
struct node {
    int l, r, len;
    ll laz1, laz2;
    ll sum;
}tree[N << 2];
void build(int l, int r, int cur) {
    tree[cur].l = l;
    tree[cur].r = r;
    tree[cur].len = r - l + 1;
    tree[cur].laz1 = 1;
    tree[cur].laz2 = 0;
    tree[cur].sum = 0;
    if(l == r) return;
    int mid = (r + l) >> 1;
    build(l, mid, cur << 1);
    build(mid + 1, r, cur << 1 | 1);
}
void pushdown(int cur) {
    if(tree[cur].laz1 != 1) {
        tree[cur << 1].laz1 *= tree[cur].laz1;
        tree[cur << 1].laz2 *= tree[cur].laz1;
        tree[cur << 1].sum *= tree[cur].laz1;
        tree[cur << 1 | 1].laz1 *= tree[cur].laz1;
        tree[cur << 1 | 1].laz2 *= tree[cur].laz1;
        tree[cur << 1 | 1].sum *= tree[cur].laz1;
        tree[cur].laz1 = 1;
    }
    if(tree[cur].laz2) {
        tree[cur << 1].laz2 += tree[cur].laz2;
        tree[cur << 1].sum += tree[cur << 1].len * tree[cur].laz2;
        tree[cur << 1 | 1].laz2 += tree[cur].laz2;
        tree[cur << 1 | 1].sum += tree[cur << 1 | 1].len * tree[cur].laz2;
        tree[cur].laz2 = 0;
    }
}
void pushup(int cur) {
    tree[cur].sum = tree[cur << 1].sum + tree[cur << 1 | 1].sum;
}
int opp;
ll val;
void update(int pl, int pr, int cur) {
    if(pl <= tree[cur].l && tree[cur].r <= pr) {
        if(opp == 1) {
            tree[cur].sum *= val;
            tree[cur].laz1 *= val;
            tree[cur].laz2 *= val;
        } else {
            tree[cur].sum += tree[cur].len * val;
            tree[cur].laz2 += val;
        }
        return;
    }
    pushdown(cur);
    if(pl <= tree[cur << 1].r) update(pl, pr, cur << 1);
    if(pr >= tree[cur << 1 | 1].l) update(pl, pr, cur << 1 | 1);
    pushup(cur);
}
int fx, fy;
void solve (int x, int y) {
    fx = pre[x], fy = pre[y];
    while(fx != fy) {
        if(deep[fx] < deep[fy]) {
            x ^= y ^= x ^= y;
            fx ^= fy ^= fx ^= fy;
        }
        update(in[fx], in[x], 1);
        x = fa[fx];
        fx = pre[x];
    }
    if(deep[x] > deep[y]) x ^= y ^= x ^= y;;
    update(in[x], in[y], 1);
}
ll query(int pl, int pr, int cur) {
    if(pl <= tree[cur].l && tree[cur].r <= pr) {
        return tree[cur].sum;
    }
    ll res = 0;
    pushdown(cur);
    if(pl <= tree[cur << 1].r) res += query(pl, pr, cur << 1);
    if(pr >= tree[cur << 1 | 1].l) res += query(pl, pr, cur << 1 | 1);
    return res;
}
  
ll solvequery(int x, int y) {
    fx = pre[x], fy = pre[y];
    ll res = 0;
    while(fx != fy) {
        if(deep[fx] < deep[fy]) {
            x ^= y ^= x ^= y;
            fx ^= fy ^= fx ^= fy;
        }
        res += query(in[fx], in[x], 1);
        x = fa[fx];
        fx = pre[x];
    }
    if(deep[x] > deep[y]) x ^= y ^= x ^= y;
    res += query(in[x], in[y], 1);
    return res;
}
int main() {
    int y;
    int op, u, v;
    ll x ;
    while(~scanf("%d", &n)) {
        init();
        for(int i = 2; i <= n; i++) {
            y = read();
            add(y, i);
            add(i, y);
        } 
        dfs1(1);     
        dfs2(1, 1);
        build(1, n, 1);
        q = read();
        while(q--) {
            op = read();
            u = read();
            v = read();
            if(op == 1) {
                x = read();
                opp = 1;
                val = x;
                solve(u, v);
            } else if(op == 2) {
                x = read();
                opp = 2;
                val = x;
                solve(u, v);
            } else if(op == 3) {
                opp = 1;
                val = -1;
                solve(u, v);
                opp = 2;
                solve(u, v); 
            } else {
                printf("%llu\n", solvequery(u, v));
            }
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值