写个树链剖分练练手
挺常规的树链剖分,注意这个线段树维护的是每个节点的权值,而不是原图中边的权值,在处理的时候注意一下处理边界就能A了
还有一些小的注意事项详细看注释
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define MAX 30010
#define INF 0x7f7f7f7f
#define LEFT (pos << 1)
#define RIGHT (pos << 1|1)
using namespace std;
const char qmax[10] = "QMAX";
const char qsum[10] = "QSUM";
const char change[10] = "CHANGE";
struct Complex{
int _max,sum;
}tree[MAX << 2];
int points,asks;
int head[MAX],total;
int _next[MAX << 1],aim[MAX << 1];
int deep[MAX],father[MAX],son[MAX]; //PreDFS处理的数组
int top[MAX],p[MAX],cnt; //DFS处理的数组
char s[10];
inline void Add(int x,int y);
int PreDFS(int x,int last,int step);
void DFS(int x,int last,int t);
void Modify(int l,int r,int x,int pos,int num);
inline int AskMax(int x,int y);
int AskMax(int l,int r,int x,int y,int pos);
inline int AskSum(int x,int y);
int AskSum(int l,int r,int x,int y,int pos); <span style="white-space:pre"> </span>//函数的重载,如果用的话一定要看清楚,别把函数调用错了
int main()
{
cin >> points;
for(int x,y,i = 1;i < points; ++i) {
scanf("%d%d",&x,&y);
Add(x,y),Add(y,x);
}
PreDFS(1,-1,1);
DFS(1,-1,1);
for(int x,i = 1;i <= points; ++i) {
scanf("%d",&x);
Modify(1,cnt,p[i],1,x);
}
cin >> asks;
for(int x,y,i = 1;i <= asks; ++i) {
scanf("%s%d%d",s,&x,&y);
if(!strcmp(s,qmax))
printf("%d\n",AskMax(x,y));
if(!strcmp(s,qsum))
printf("%d\n",AskSum(x,y));
if(!strcmp(s,change))
Modify(1,cnt,p[x],1,y);
}
return 0;
}
inline void Add(int x,int y)
{
_next[++total] = head[x];
aim[total] = y;
head[x] = total;
}
int PreDFS(int x,int last,int step)
{
int max_size = 0,p_son = 0,re = 1; //这里re=1,每次写都忘记,然后调试出来……千万要记住啊
father[x] = last;
deep[x] = step;
for(int i = head[x];i;i = _next[i]) {
if(aim[i] == last) continue;
int temp = PreDFS(aim[i],x,step + 1);
re += temp;
if(temp > max_size)
max_size = temp,p_son = aim[i];
}
son[x] = p_son;
return re;
}
void DFS(int x,int last,int t)
{
p[x] = ++cnt;
top[x] = t;
if(son[x]) DFS(son[x],x,t);
for(int i = head[x];i;i = _next[i]) {
if(aim[i] == last || aim[i] == son[x]) continue;
DFS(aim[i],x,aim[i]);
}
}
void Modify(int l,int r,int x,int pos,int num)
{
if(l == r && l == x) {
tree[pos].sum = tree[pos]._max = num;
return ;
}
int mid = (l + r) >> 1;
if(x <= mid) Modify(l,mid,x,LEFT,num);
else Modify(mid + 1,r,x,RIGHT,num);
tree[pos].sum = tree[LEFT].sum + tree[RIGHT].sum;
tree[pos]._max = max(tree[LEFT]._max,tree[RIGHT]._max);
}
inline int AskMax(int x,int y)
{
int re = -INF; //注意这里的初值
int fx = top[x],fy = top[y];
while(fx != fy) {
if(deep[fx] < deep[fy])
swap(fx,fy),swap(x,y);
re = max(re,AskMax(1,cnt,p[fx],p[x],1));
x = father[fx];
fx = top[x];
}
if(deep[x] < deep[y]) swap(x,y);
re = max(re,AskMax(1,cnt,p[y],p[x],1));
return re;
}
int AskMax(int l,int r,int x,int y,int pos)
{
if(l == x && r == y)
return tree[pos]._max;
int mid = (l + r) >> 1;
if(y <= mid) return AskMax(l,mid,x,y,LEFT);
if(x > mid) return AskMax(mid + 1,r,x,y,RIGHT);
int left = AskMax(l,mid,x,mid,LEFT);
int right = AskMax(mid + 1,r,mid + 1,y,RIGHT);
return max(left,right);
}
inline int AskSum(int x,int y)
{
int re = 0;
int fx = top[x],fy = top[y];
while(fx != fy) {
if(deep[fx] < deep[fy])
swap(fx,fy),swap(x,y);
re += AskSum(1,cnt,p[fx],p[x],1);
x = father[fx];
fx = top[x];
}
if(deep[x] < deep[y]) swap(x,y);
re += AskSum(1,cnt,p[y],p[x],1);
return re;
}
int AskSum(int l,int r,int x,int y,int pos)
{
if(l == x && r == y)
return tree[pos].sum;
int mid = (l + r) >> 1;
if(y <= mid) return AskSum(l,mid,x,y,LEFT);
if(x > mid) return AskSum(mid + 1,r,x,y,RIGHT);
int left = AskSum(l,mid,x,mid,LEFT);
int right = AskSum(mid + 1,r,mid + 1,y,RIGHT);
return left + right;
}