BZOJ 3531 SDOI 2014 旅行

题目大意

给出一个树,树上每个节点有两个权值,分别是这个节点的宗教评级和这个节点信仰的宗教。多次修改这两个权值,每次询问树上路径上的点的同一个宗教的最大评级和评级和。

思路

不要想太多,每个宗教建立一颗线段树,空间开不下考虑一下动态节点线段树。之后在每个线段树上维护一下树链剖分就行了。
你们想知道c的取值范围么?
[0,10^5]

CODE

#define _CRT_SECURE_NO_WARNINGS

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 100010
using namespace std;

struct SegTree *nil;

struct SegTree{
    SegTree *son[2];
    int _max,sum;

    SegTree() {
        _max = sum = 0;
        son[0] = son[1] = nil;
    }

    void Modify(int l,int r,int x,int c) {
        if(l == r) {
            _max = sum = c;
            return ;
        }
        int mid = (l + r) >> 1;
        if(x <= mid) {   
            if(son[0] == nil)
                son[0] = new SegTree();
            son[0]->Modify(l,mid,x,c);
        }
        else {
            if(son[1] == nil)
                son[1] = new SegTree();
            son[1]->Modify(mid + 1,r,x,c);
        }
        _max = max(son[0]->_max,son[1]->_max);
        sum = son[0]->sum + son[1]->sum;
    }
    int GetSum(int l,int r,int x,int y) {
        if(this == nil) return 0;
        if(l == x && y == r)    return sum;
        int mid = (l + r) >> 1;
        if(y <= mid) return son[0]->GetSum(l,mid,x,y);
        if(x > mid)      return son[1]->GetSum(mid + 1,r,x,y);
        int left = son[0]->GetSum(l,mid,x,mid);
        int right = son[1]->GetSum(mid + 1,r,mid + 1,y);
        return left + right;
    }
    int GetMax(int l,int r,int x,int y) {
        if(this == nil) return 0;
        if(l == x && y == r)    return _max;
        int mid = (l + r) >> 1;
        if(y <= mid) return son[0]->GetMax(l,mid,x,y);
        if(x > mid)      return son[1]->GetMax(mid + 1,r,x,y);
        int left = son[0]->GetMax(l,mid,x,mid);
        int right = son[1]->GetMax(mid + 1,r,mid + 1,y);
        return max(left,right);
    }
}none,*root[MAX];

int points,asks;
int head[MAX],total;
int _next[MAX << 1],aim[MAX << 1];

inline void Add(int x,int y)
{
    _next[++total] = head[x];
    aim[total] = y;
    head[x] = total;
}

int p[MAX],belief[MAX];

int size[MAX],son[MAX],father[MAX],deep[MAX];
int top[MAX],pos[MAX],cnt;

void PreDFS(int x,int last)
{
    deep[x] = deep[last] + 1;
    father[x] = last;
    size[x] = 1;
    int max_size = 0;
    for(int i = head[x]; i; i = _next[i]) {
        if(aim[i] == last)  continue;
        PreDFS(aim[i],x);
        size[x] += size[aim[i]];
        if(size[aim[i]] > max_size)
            max_size = size[aim[i]],son[x] = aim[i];
    }
}

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]);
    }
}

inline int GetSum(int x,int y,int p)
{
    int re = 0;
    while(top[x] != top[y]) {
        if(deep[top[x]] < deep[top[y]])  swap(x,y);
        re += root[p]->GetSum(1,points,pos[top[x]],pos[x]);
        x = father[top[x]];
    }
    if(deep[x] < deep[y])    swap(x,y);
    re += root[p]->GetSum(1,points,pos[y],pos[x]);
    return re;
}

inline int GetMax(int x,int y,int p)
{
    int re = 0;
    while(top[x] != top[y]) {
        if(deep[top[x]] < deep[top[y]])  swap(x,y);
        re = max(re,root[p]->GetMax(1,points,pos[top[x]],pos[x]));
        x = father[top[x]];
    }
    if(deep[x] < deep[y])    swap(x,y);
    re = max(re,root[p]->GetMax(1,points,pos[y],pos[x]));
    return re;
}

char s[10];

int main()
{

    nil = &none;

    cin >> points >> asks;
    for(int i = 0; i < MAX; ++i)
        root[i] = new SegTree();
    for(int i = 1; i <= points; ++i)
        scanf("%d%d",&p[i],&belief[i]);
    for(int x,y,i = 1; i < points; ++i) {
        scanf("%d%d",&x,&y);
        Add(x,y),Add(y,x);
    }
    PreDFS(1,0);
    DFS(1,0,1);
    for(int i = 1; i <= points; ++i)
        root[belief[i]]->Modify(1,points,pos[i],p[i]);
    for(int x,y,i = 1; i <= asks; ++i) {
        scanf("%s%d%d",s,&x,&y);
        if(s[0] == 'C' && s[1] == 'C') {
            root[belief[x]]->Modify(1,points,pos[x],0);
            root[belief[x] = y]->Modify(1,points,pos[x],p[x]);
        }
        else if(s[0] == 'C' && s[1] == 'W')
            root[belief[x]]->Modify(1,points,pos[x],p[x] = y);
        else if(s[0] == 'Q' && s[1] == 'S')
            printf("%d\n",GetSum(x,y,belief[x]));
        else
            printf("%d\n",GetMax(x,y,belief[x]));
    }
    return 0;
}

你可能感兴趣的:(树链剖分,bzoj,动态节点线段树,SDOI2014)