树链剖分看了半个星期,感觉自己可以上题了
轻重链划分倒是一下就看懂了,两遍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 */