ACM-ICPC 2018 焦作赛区网络预赛 E. Jiu Yuan Wants to Eat (树链剖分)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lingzidong/article/details/82747452

题目链接:https://nanti.jisuanke.com/t/31714
题意就是给一个树,一开始点权都是0,然后有4个操作:树上路径加,乘,取反,输出路径和。答案对2^64取模首先加法乘法结合在一起其实比较好解决,用好线段树标记就行。现在来解决取反的问题,如果一点点取反肯定超时,所以我们是否能将取反转化成简单的加乘操作。首先!x = (2 ^64 - 1) - x,其次 (!x) % (2 ^ 64-1) = (2 ^64 -1)*x % (2 ^ 64) ,代入。发现!x = (2 ^64-1)*x + (2 ^64-1), 这样就转化成了线性的操作。
当时应该选择写这道题,当时的确没有想到正确的更新方式,实际上应该多利用题目中给的特殊条件来判断这个题如何来写。

#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
#include <queue>
#include <map>
#define ll long long
#define ull unsigned long long
#define mask 0xffffffffffffffff
using namespace std;
const int MAXN = 1 << 17;
struct Edge
{
    int to,next;
}edge[MAXN * 2];
int head[MAXN],tot;
int top[MAXN];
int fa[MAXN];
int deep[MAXN];
int num[MAXN];
int p[MAXN];
int fp[MAXN];
int son[MAXN];
int pos;
int n;
void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
    pos = 0;
    memset(son,-1,sizeof(son));
}
void addedge(int u,int v)
{
    edge[tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot++;
}
void dfs(int u,int pre,int d)
{
    deep[u] = d;
    fa[u] = pre;
    num[u] = 1;
    for(int i = head[u];i != -1;i = edge[i].next)
    {
        int v = edge[i].to;
        if(v == pre) continue;
        dfs(v,u,d+1);
        num[u] += num[v];
        if(son[u] == -1 || num[v] > num[son[u]])
        {
            son[u] = v;
        }
    }
}
void getpos(int u,int sp)
{
    top[u] = sp;
    p[u] = ++pos;
    fp[p[u]] = u;
    if(son[u] == -1) return;
    getpos(son[u],sp);
    for(int i = head[u];i != -1;i = edge[i].next)
    {
        int v = edge[i].to;
        if(v != son[u] && v != fa[u])
            getpos(v,v);
    }
}
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
ull sum[MAXN<<2];
ull add[MAXN<<2],mul[MAXN<<2];
void push_up(int rt)
{
    sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void push_down(int rt,int m)
{
    if(add[rt] != 0 || mul[rt] != 1)
    {
        add[rt<<1] = (mul[rt] * add[rt<<1] + add[rt]);
        add[rt<<1|1] = (mul[rt] * add[rt<<1|1] + add[rt]);
        mul[rt<<1] = mul[rt<<1] * mul[rt];
        mul[rt<<1|1] = mul[rt<<1|1] * mul[rt];
        sum[rt<<1] = mul[rt]*sum[rt<<1] + add[rt]*(m - (m >>1));
        sum[rt<<1|1] = mul[rt]*sum[rt<<1|1] + add[rt]*(m>>1);

        mul[rt] = 1,add[rt] = 0;
    }
}
void build(int l,int r,int rt)
{
    add[rt] = 0;
    mul[rt] = 1;
    sum[rt] = 0;
    if(l == r) return;
    int mid = (l +r ) >> 1;
    build(lson);
    build(rson);
    push_up(rt);
}
void update(int op,int L,int R,ull val,int l,int r,int rt)
{
    if(L <= l && r <= R)
    {
        if(op == 1)
        {
            add[rt] *= val;
            mul[rt] *= val;
            sum[rt] *= val;
        }
        else
        {
            add[rt] += val;
            sum[rt] += val*(r - l+1);
        }
        return;
    }
    push_down(rt,r - l +1);
    int mid = (l +r)>>1;
    if(L <= mid) update(op,L,R,val,lson);
    if(R > mid) update(op,L,R,val,rson);
    push_up(rt);
}
ull query(int L,int R,int l,int r,int rt)
{
    if(L <= l && r <= R)
    {
        return sum[rt];
    }
    push_down(rt,r - l +1);
    int mid = (l +r )>>1;
    ull res = 0;
    if(L <= mid) res += query(L,R,lson);
    if(R > mid) res += query(L,R,rson);
    return res;
}
void change(int u,int v,ull val,int op)
{
    while(top[u] != top[v])
    {
        if(deep[top[u]] < deep[top[v]]) swap(u,v);
        update(op,p[top[u]],p[u],val,1,n,1);
        u = fa[top[u]];
    }
    if(deep[u] > deep[v]) swap(u,v);
    update(op,p[u],p[v],val,1,n,1);
}
ull ask(int u,int v)
{
    ull tmp = 0;
    while(top[u] != top[v])
    {
        if(deep[top[u]] < deep[top[v]])
        {
            swap(u,v);
        }
        tmp += query(p[top[u]],p[u],1,n,1);
        u = fa[top[u]];
    }
    if(deep[u] > deep[v]) swap(u,v);
    tmp += query(p[u],p[v],1,n,1);
    return tmp;
}
int main()
{
    while(scanf("%d",&n) != EOF)
    {
        init();
        for(int i = 2;i<=n;i++)
        {
            int b;
            scanf("%d",&b);
            addedge(b,i);
            addedge(i,b);
        }
        dfs(1,1,0);
        getpos(1,1);
        build(1,n,1);
        int q;
        scanf("%d",&q);
        while(q--)
        {
            int op,u,v;
            ull x;
            scanf("%d%d%d",&op,&u,&v);
            if(op == 1 || op == 2)
            {
                scanf("%llu",&x);
                change(u,v,x,op);
            }
            else if(op == 3)
            {
                change(u,v,mask,1);
                change(u,v,mask,2);
            }
            else
            {
                printf("%llu\n",ask(u,v));
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lingzidong/article/details/82747452