现在的位置: 首页 > 综合 > 正文

BZOJ 2157 旅游 树链剖分

2017年10月16日 ⁄ 综合 ⁄ 共 3467字 ⁄ 字号 评论关闭

题目大意:给出一棵树,支持以下操作:1.改变一条边的边权。2.将x到y路径的权值取反。3.查询x到y路径上最大值,最小值和权值和。

思路:好裸的链剖水题啊,唯一麻烦一点地是权值放在了边上,注意一下处理就没问题了。。

CODE:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 40010
#define INF 0x3f3f3f3f
using namespace std;
#define LEFT (pos << 1)
#define RIGHT (pos << 1|1)
#define min(a,b) ((a) < (b) ? (a):(b))
#define max(a,b) ((a) > (b) ? (a):(b))
 
int points,asks;
int head[MAX],total;
int _next[MAX << 1],aim[MAX << 1];
 
struct Edge{
    int x,y,len;
    int pos;
 
    Edge(int _,int __,int ___):x(_),y(__),len(___) {}
    Edge() {}
}edge[MAX];
 
inline void Add(int x,int y)
{
    _next[++total] = head[x];
    aim[total] = y;
    head[x] = total;
}
 
int father[MAX],deep[MAX],son[MAX],size[MAX];
 
void _DFS(int x,int last)
{
    father[x] = last;
    deep[x] = deep[last] + 1;
    size[x] = 1;
    int max_size = 0;
    for(int i = head[x]; i; i = _next[i]) {
        if(aim[i] == last)  continue;
        _DFS(aim[i],x);
        size[x] += size[aim[i]];
        if(size[aim[i]] > max_size)
            max_size = size[aim[i]],son[x] = aim[i];
    }
}
 
int pos[MAX],top[MAX],cnt;
 
void DFS(int x,int last,int _top)
{
    pos[x] = ++cnt;
    top[x] = _top;
    if(son[x])  DFS(son[x],x,_top);
    for(int i = head[x]; i; i = _next[i]) {
        if(aim[i] == last || aim[i] == son[x])  continue;
        DFS(aim[i],x,aim[i]);
    }
}
 
struct SegTree{
    int sum,_min,_max;
    bool inv;
 
    SegTree(int _ = 0,int __ = INF,int ___ = -INF):sum(_),_min(__),_max(___) {}
    void Inv() {
        inv ^= 1;
        sum *= -1;
        int t = _max;
        _max = -_min;
        _min = -t;
    }
}tree[MAX << 2];
 
inline void PushUp(int pos)
{
    tree[pos].sum = tree[LEFT].sum + tree[RIGHT].sum;
    tree[pos]._min = min(tree[LEFT]._min,tree[RIGHT]._min);
    tree[pos]._max = max(tree[LEFT]._max,tree[RIGHT]._max);
}
 
inline SegTree PushUp(SegTree a,SegTree b)
{
    SegTree re;
    re.sum = a.sum + b.sum;
    re._min = min(a._min,b._min);
    re._max = max(a._max,b._max);
    return re;
}
 
inline void PushDown(int pos)
{
    if(tree[pos].inv) {
        tree[LEFT].Inv();
        tree[RIGHT].Inv();
        tree[pos].inv = false;
    }
}
 
void Modify(int l,int r,int x,int pos,int c)
{
    if(l == r) {
        tree[pos].sum = tree[pos]._min = tree[pos]._max = c;
        return ;
    }
    PushDown(pos);
    int mid = (l + r) >> 1;
    if(x <= mid) Modify(l,mid,x,LEFT,c);
    else    Modify(mid + 1,r,x,RIGHT,c);
    PushUp(pos);
}
 
void Change(int l,int r,int x,int y,int pos)
{
    if(l == x && r == y) {
        tree[pos].Inv();
        return ;
    }
    PushDown(pos);
    int mid = (l + r) >> 1;
    if(y <= mid) Change(l,mid,x,y,LEFT);
    else if(x > mid) Change(mid + 1,r,x,y,RIGHT);
    else {
        Change(l,mid,x,mid,LEFT);
        Change(mid + 1,r,mid + 1,y,RIGHT);
    }
    PushUp(pos);
}
 
inline void Change(int x,int y)
{
    while(top[x] != top[y]) {
        if(deep[top[x]] < deep[top[y]])
            swap(x,y);
        Change(1,points,pos[top[x]],pos[x],1);
        x = father[top[x]];
    }
    if(x == y)  return ;
    if(deep[x] < deep[y])    swap(x,y);
    Change(1,points,pos[y] + 1,pos[x],1);
}
 
SegTree Ask(int l,int r,int x,int y,int pos)
{
    if(l == x && r == y)    return tree[pos];
    PushDown(pos);
    int mid = (l + r) >> 1;
    if(y <= mid) return Ask(l,mid,x,y,LEFT);
    if(x > mid)      return Ask(mid + 1,r,x,y,RIGHT);
    SegTree left = Ask(l,mid,x,mid,LEFT);
    SegTree right = Ask(mid + 1,r,mid + 1,y,RIGHT);
    return PushUp(left,right);
}
 
inline SegTree Ask(int x,int y)
{
    SegTree re(0,INF,-INF);
    while(top[x] != top[y]) {
        if(deep[top[x]] < deep[top[y]])
            swap(x,y);
        re = PushUp(re,Ask(1,points,pos[top[x]],pos[x],1));
        x = father[top[x]]; 
    }
    if(x == y)  return re;
    if(deep[x] < deep[y])    swap(x,y);
    re = PushUp(re,Ask(1,points,pos[y] + 1,pos[x],1));
    return re;
}
 
char c[10];
 
int main()
{
    cin >> points;
    for(int x,y,z,i = 1; i < points; ++i) {
        scanf("%d%d%d",&x,&y,&z);
        x++,y++;
        Add(x,y),Add(y,x);
        edge[i] = Edge(x,y,z);
    }
    _DFS(1,0);
    DFS(1,0,1);
    for(int i = 1; i < points; ++i) {
        edge[i].pos = deep[edge[i].x] > deep[edge[i].y] ? pos[edge[i].x]:pos[edge[i].y];
        Modify(1,points,edge[i].pos,1,edge[i].len);
    }
    cin >> asks;
    for(int x,y,i = 1; i <= asks; ++i) {
        scanf("%s%d%d",c,&x,&y);
        if(c[0] == 'C') Modify(1,points,edge[x].pos,1,y);
        else if(c[0] == 'N')    Change(x + 1,y + 1);
        else {
            SegTree ans = Ask(x + 1,y + 1);
            if(c[0] == 'S')         printf("%d\n",ans.sum);
            else if(c[1] == 'I')    printf("%d\n",ans._min);
            else                    printf("%d\n",ans._max);
        }
    }
    return 0;
}

抱歉!评论已关闭.