树链剖分看了半个星期,感觉自己可以上题了
轻重链划分倒是一下就看懂了,两遍dfs的剖分应该都卡不住(刚开始以为是子树中最深的那个为重链的我也是图样)(其实是子树结点更多的那个)
但是卡在了树上的查询上,怎么也理解不了怎么做到不重不漏,感觉总是有一个迷の情况会多询问一个节点或少询问一个节点
终于有一天感觉自己不能这样想下去了(然后拿出了草稿纸),在纸上自己推了一发,然后发现了树剖的循环不变式!(大雾
就是每次从链顶到链顶的父亲的时候,链顶的父亲总是没有被更新的,(如果用灰色来表示未询问的点,黑色表示已经查询过了的点,那么每次走上来的时候所站的地方都是灰色的点,也就是说,和刚开始的情况是一样一样的
然后就木有了。。。。
至少对我来说树剖只有这个地方卡了我一下
感觉kuangbin大神的一句话说的很好,树剖只是一些区间算法在树上的应用罢了
这个题也是很裸的模板,区间和还有区间最值的查询在线段树上也是挺裸的东西,就不细说了
以及代码
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
const int INF = 0x3f3f3f3f;
const int maxn = 112345;
vector<int> edge[maxn];
void init(int n){
for(int i=0;i<=n;i++)
edge[i].resize(0);
}
void Link(int st,int ed){
edge[st].push_back(ed);
edge[ed].push_back(st);
}
struct Info{
int m,s;
Info(){
m=-INF,s=0;
}
void out(){
printf("max = %lld sum = %lld\n",m,s);
}
};
#define debug123
Info operator + (const Info &a,Info b){
b.s+=a.s;
b.m=max(b.m,a.m);
return b;
}
Info val[maxn*4];
#define lson o<<1,l,m
#define rson o<<1|1,m+1,r
#define root 1,1,n
#define Now int o,int l,int r
#define Mid int m = l + (r-l)/2
void update(Now,int up,int uv){
if(l==r){
val[o].m=val[o].s=uv;
return;
}
Mid;
if(up<=m)
update(lson,up,uv);
else
update(rson,up,uv);
val[o]=val[o<<1]+val[o<<1|1];
}
Info query(Now,int ql,int qr){
if(ql<=l && r<=qr){
return val[o];
}
Info ret;
Mid;
if(ql<=m)
ret = ret+query(lson,ql,qr);
if(m+1<=qr)
ret = ret+query(rson,ql,qr);
return ret;
}
int son[maxn],fa[maxn],top[maxn],sid[maxn],siz[maxn],deep[maxn];
int _cnt;
void dffs(int st,int Fa,int Deep){
deep[st]=Deep,fa[st]=Fa,siz[st]=1;
for(vector<int>::iterator it = edge[st].begin();it!=edge[st].end();it++){
int x = *it;
if(x!=Fa){
dffs(x,st,Deep+1);
siz[st]+=siz[x];
if(son[st]==-1 || siz[son[st]] < siz[x]){
son[st]=x;
}
}
}
}
void dfss(int st,int tp){
top[st]=tp,sid[st]=_cnt++;
if(son[st]!=-1)
dfss(son[st],tp);
for(vector<int>::iterator it = edge[st].begin();it!=edge[st].end();it++){
int x = *it;
if(x!=fa[st] && x!=son[st]){
dfss(x,x);
}
}
}
void splite(){
memset(son,-1,sizeof(son));
_cnt=1;
dffs(1,0,1);
dfss(1,1);
}
void upd(int p,int v,int n){
update(root,sid[p],v);
}
Info que(int x,int y,int n){
Info ret;
int tx = top[x];
int ty = top[y];
while(tx!=ty){
if(deep[tx] > deep[ty]){ //up x
ret = ret + query(root,sid[tx],sid[x]);
x = fa[tx],tx = top[x];
}
else{
ret = ret + query(root,sid[ty],sid[y]);
y = fa[ty],ty = top[y];
}
#ifdef debug
ret.out();
#endif
}
if(deep[x] > deep[y]){
ret = ret + query(root,sid[y],sid[x]);
}
else{
ret = ret + query(root,sid[x],sid[y]);
}
#ifdef debug
printf("after x = %d y = %d\n",x,y);
ret.out();
#endif
return ret;
}
#ifdef debug
void out(char *nam,int *s,int n){
puts(nam);
for(int i=1;i<=n;i++)
printf(i<n?"%d ":"%d\n",s[i]);
}
#endif
int main(){
int n,m;
char ord[20];
scanf("%d",&n);
init(n);
int x,y;
for(int i=1;i<n;i++){
scanf("%d %d",&x,&y);
Link(x,y);
}
splite();
#ifdef debug
out("fa",fa,n);
out("son",son,n);
out("top",top,n);
out("deep",deep,n);
#endif
for(int i=1;i<=n;i++){
scanf("%d",&x);
upd(i,x,n);
}
scanf("%d\n",&m);
while(m--){
scanf("%s",ord);
scanf("%d %d",&x,&y);
if(ord[0]=='Q'){
Info ans = que(x,y,n);
if(ord[1]=='M')
printf("%d\n",ans.m);
else
printf("%d\n",ans.s);
}
else{
upd(x,y,n);
}
}
return 0;
}
/*
10
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
9 10
1 1 1 1 1 1 1 1 1 1
10086
QMAX 1 3
QMAX 1 10
QSUM 3 4
CHANGE 3 6
QMAX 1 3
QMAX 1 10
QSUM 3 4
7
1 2
2 3
3 4
1 5
5 6
6 7
1 1 1 1 1 1 1
10086
QSUM 4 7
QMAX 4 7
QSUM 2 6
CHANGE 1 12
QSUM 4 7
QMAX 4 7
QSUM 2 6
CHANGE 7 10086
QSUM 4 7
QMAX 4 7
QSUM 2 6
*/