HYSBZ 1036 树的统计Count

树链剖分看了半个星期,感觉自己可以上题了

轻重链划分倒是一下就看懂了,两遍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
*/


你可能感兴趣的:(HYSBZ 1036 树的统计Count)