poj 3237 Tree(树链剖分)

wa了半天。。懒惰标记那里要用异或来修改,wa的时候突然想到,万一两次反转相同的区间,反转就取消了,然而我的懒惰标记那里一直col[rt]=1,这样反转就没有取消。。。这里写图片描述

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

const int MAXN = 1e5+10;
const int INF = 0x3f3f3f3f;

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;

void init()
{
    tot = 0;
    memset(head,-1,sizeof(head));
    pos = 1;
    memset(son,-1,sizeof(son));
}
void addedge(int u,int v)
{
    edge[tot].to = v;
    edge[tot].next = head[u];
    head[u] = tot++;
}

void dfs1(int u, int pre, int dep)
{
    deep[u] = dep;
    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;
        dfs1(v,u,dep+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);
    }
}

int e[MAXN][3];
int n;
char op[15];
int maxn[MAXN<<2];
int minn[MAXN<<2];
int col[MAXN<<2];

void pushUp(int rt)
{
    maxn[rt] = max(maxn[rt<<1], maxn[rt<<1|1]);
    minn[rt] = min(minn[rt<<1], minn[rt<<1|1]);
}

void pushDown(int rt)
{
    if(col[rt])
    {
        col[rt] = 0;
        col[rt<<1] ^= 1;
        col[rt<<1|1] ^= 1;
        maxn[rt<<1] = -maxn[rt<<1];
        minn[rt<<1] = -minn[rt<<1];
        swap(maxn[rt<<1],minn[rt<<1]);
        maxn[rt<<1|1] = -maxn[rt<<1|1];
        minn[rt<<1|1] = -minn[rt<<1|1];
        swap(maxn[rt<<1|1],minn[rt<<1|1]);
    }
}

void update(int pos, int val, int l, int r, int rt)
{
    if(l == r)
    {
        minn[rt] = maxn[rt] = val;
        return;
    }
    pushDown(rt);
    int mid = (l+r) >> 1;
    if(pos <= mid) update(pos,val,l,mid,rt<<1);
    else update(pos,val,mid+1,r,rt<<1|1);
    pushUp(rt);
}

void updateTwo(int L, int R, int l, int r, int rt)
{
    if(l >= L && r <= R)
    {
        maxn[rt] = -maxn[rt];
        minn[rt] = -minn[rt];
        swap(maxn[rt],minn[rt]);
        col[rt] ^= 1;
        return;
    }
    pushDown(rt);
    int mid = (l+r) >> 1;
    if(L <= mid) updateTwo(L,R,l,mid,rt<<1);
    if(R > mid) updateTwo(L,R,mid+1,r,rt<<1|1);
    pushUp(rt);
}

int query(int L, int R, int l, int r, int rt)
{
    if(l >= L && r <= R)
        return maxn[rt];
    pushDown(rt);
    int mid = (l+r) >> 1;
    int ret = -INF;
    if(L <= mid) ret = max(ret,query(L,R,l,mid,rt<<1));
    if(R > mid) ret = max(ret,query(L,R,mid+1,r,rt<<1|1));
    return ret;
}

int Calc(int u, int v)
{
    int f1 = top[u],f2 = top[v];
    int ret = -INF;
    while(f1 != f2)
    {
        if(deep[f1] < deep[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        ret = max(ret,query(p[f1],p[u],1,n,1));
        u = fa[f1];
        f1 = top[u];
    }
    if(u == v) return ret;
    if(deep[u] > deep[v]) swap(u,v);
    ret = max(ret,query(p[son[u]],p[v],1,n,1));
    return ret;
}

void flip(int u, int v)
{
    int f1 = top[u],f2 = top[v];
    while(f1 != f2)
    {
        if(deep[f1] < deep[f2])
        {
            swap(f1,f2);
            swap(u,v);
        }
        updateTwo(p[f1],p[u],1,n,1);
        u = fa[f1];
        f1 = top[u];
    }
    if(u == v) return;
    if(deep[u] > deep[v]) swap(u,v);
    updateTwo(p[son[u]],p[v],1,n,1);
}

int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        init();
        memset(maxn,0,sizeof(maxn));
        memset(minn,0,sizeof(minn));
        memset(col,0,sizeof(col));

        scanf("%d",&n);
        for(int i = 1; i < n; ++i)
        {
            scanf("%d %d %d",&e[i][0],&e[i][1],&e[i][2]);
            addedge(e[i][0],e[i][1]);
            addedge(e[i][1],e[i][0]);
        }
        dfs1(1,0,0);
        getpos(1,1);
        for(int i = 1; i < n; ++i)
        {
            if(deep[e[i][0]] > deep[e[i][1]])
                swap(e[i][0],e[i][1]);
            update(p[e[i][1]],e[i][2],1,n,1);
        }
        int u,v;
        while(scanf("%s",op) && op[0] != 'D')
        {
            scanf("%d %d",&u,&v);
            //最值查询
            if(op[0] == 'Q')
                printf("%d\n",Calc(u,v));
            //单点修改
            else if(op[0] == 'C')
                update(p[e[u][1]],v,1,n,1);
            //区间取相反数
            else
                flip(u,v);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值