【BZOJ】【P3531】【SDOI2014】【旅行】【题解】【树链剖分】

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3531

考场上爆零,发奋学链剖,然后水过……

感谢GreenClouds神犇教我的动态开点的线段树

递归的链剖会在链的时候爆栈,蒟蒻YY了一个非递归的,见代码

Code:

#include<cstdio>
#include<stack>
#include<deque>
#include<vector>
#include<iostream>
#include<algorithm>
#define X first
#define Y second
using namespace std;
const int maxn=100100;
vector<int>G[maxn];
typedef pair<int,int> pii;
void add(int u,int v){
	G[u].push_back(v);
	G[v].push_back(u);
}
int top[maxn],w[maxn],fa[maxn],son[maxn],siz[maxn],dep[maxn],z=0;
int n,q;
int W[maxn],C[maxn];

//递归版 
/*
void dfs(const int &u){
	son[u]=0;siz[u]=1;
	for(int i=0;i<G[u].size();i++){
		const int &v=G[u][i];
		if(v!=fa[u]){
			fa[v]=u;
			dep[v]=dep[u]+1;
			dfs(v);
			if(siz[son[u]]<siz[v])son[u]=v;
			siz[u]+=siz[v];
		}
	}
}*/

//GTY神犇版 
/*
inline void dfs(int root,int BigBoss)
{
    memset(cur,-1,sizeof(cur));
    int now=root;
    while (now!=f[root])
    {
        if (cur[now]==-1) 
        {
            cur[now]=point[now];
            boss[now]=BigBoss;
            bossson[BigBoss]++;
            NewSon(now);
        }
        else cur[now]=next[cur[now]];
        if (cur[now]&&v[cur[now]]==f[now]) cur[now]=next[cur[now]];
        if (!cur[now])
        {
            now=f[now];
            continue;
        }
        f[v[cur[now]]]=now;
        now=v[cur[now]];
    }
}*/
//YY的非递归#1 
int order[maxn];
stack<int>S;
void dfs(int u){
	S.push(u);
	order[0]=0;
	while(!S.empty()){
		int u=S.top();S.pop();
		son[u]=0;siz[u]=1;
		for(int i=0;i<G[u].size();i++){
			int v=G[u][i];
			if(v!=fa[u]){
				dep[v]=dep[u]+1;
				fa[v]=u;
				S.push(v);
				order[++order[0]]=v;			
			}
		}
	}
	for(int i=order[0];i>=1;i--){
		int u=order[i];
		if(siz[son[fa[u]]]<siz[u])son[fa[u]]=u;
		siz[fa[u]]+=siz[u];
	}
}
//递归版 
/*
void build(int u,int tp){
	w[u]=++z;top[u]=tp;
	if(son[u])build(son[u],tp);
	for(int i=0;i<G[u].size();i++){
		int v=G[u][i];
		if(v!=fa[u]&&v!=son[u])build(v,v);
	}
}*/
//YY的非递归#2 
deque<pii>Q;
void build(int u,int tp){
	Q.push_front(pii(u,tp));
	while(!Q.empty()){
		pii t=Q.front();Q.pop_front();
		int u=t.X,tp=t.Y;
		w[u]=++z;top[u]=tp;
		if(son[u])Q.push_front(pii(son[u],tp));
		for(int i=0;i<G[u].size();i++){
			int v=G[u][i];
			if(v!=fa[u]&&v!=son[u])
			Q.push_back(pii(v,v));
		}
	}
}

int V=0;
struct seg_tree{
	struct node{
		int l,r,sum,m;
		node(){l=0;r=0;sum=0;m=0;}
	};
	node t[3010000];
	void rz(int x){
		t[x].sum=t[t[x].l].sum+t[t[x].r].sum;
		t[x].m=max(t[t[x].l].m,t[t[x].r].m);
	}
	void change(int l,int r,int pos,int val,int &c){
		if(l>r)return;
		if(!c)c=++V;
		if(l==r){
			t[c].sum=t[c].m=val;
			return;
		}int mid=l+r>>1;
		if(pos<=mid)change(l,mid,pos,val,t[c].l);
		else change(mid+1,r,pos,val,t[c].r);
		rz(c);
	}
	int qsum(int l,int r,int l0,int r0,int &c){
		if(c==0)return 0;
		if(l>r)return 0;
		if(l0<=l&&r0>=r)
			return t[c].sum;
		int mid=l+r>>1;
		int ans=0;
		if(l0<=mid)ans+=qsum(l,mid,l0,r0,t[c].l);
		if(r0>mid) ans+=qsum(mid+1,r,l0,r0,t[c].r);
		return ans;
	}
	int qmax(int l,int r,int l0,int r0,int &c){
		if(c==0)return 0;
		if(l>r)return 0;
		if(l0<=l&&r0>=r)
			return t[c].m;
		int mid=l+r>>1;
		int ans=0;
		if(l0<=mid)ans=max(ans,qmax(l,mid,l0,r0,t[c].l));
		if(r0>mid) ans=max(ans,qmax(mid+1,r,l0,r0,t[c].r));
		return ans;		
	}
}T;
int Tr[maxn];
void CC(int x,int c){
	T.change(1,n,w[x],0,Tr[C[x]]);
	C[x]=c;
	T.change(1,n,w[x],W[x],Tr[C[x]]);
}
void CW(int x,int ww){
	W[x]=ww;
	T.change(1,n,w[x],ww,Tr[C[x]]);
}
int QS(int u,int v){
	int ans=0;int c=C[u];
	while(top[u]!=top[v]){
		if(dep[top[u]]>dep[top[v]]){
			int a=w[u],b=w[top[u]];
			if(a>b)swap(a,b);
			ans+=T.qsum(1,n,a,b,Tr[c]);
			u=fa[top[u]];
		}else{
			int a=w[v],b=w[top[v]];
			if(a>b)swap(a,b);
			ans+=T.qsum(1,n,a,b,Tr[c]);			
			v=fa[top[v]];
		}
	}
	int a=w[u],b=w[v];
	if(a>b)swap(a,b);
	ans+=T.qsum(1,n,a,b,Tr[c]);
	return ans;
}
int QM(int u,int v){
	int ans=0;int c=C[u];
	while(top[u]!=top[v]){
		if(dep[top[u]]>dep[top[v]]){
			int a=w[u],b=w[top[u]];
			if(a>b)swap(a,b);
			ans=max(ans,T.qmax(1,n,a,b,Tr[c]));
			u=fa[top[u]];
		}else{
			int a=w[v],b=w[top[v]];
			if(a>b)swap(a,b);
			ans=max(ans,T.qmax(1,n,a,b,Tr[c]));		
			v=fa[top[v]];
		}
	}
	int a=w[u],b=w[v];
	if(a>b)swap(a,b);
	ans=max(ans,T.qmax(1,n,a,b,Tr[c]));
	return ans;	
}
int main(){
//	freopen("Q3.in","r",stdin);
	scanf("%d%d",&n,&q);
	for(int i=1;i<=n;i++)
		scanf("%d%d",&W[i],&C[i]);
	for(int i=1;i<n;i++){
		int u,v;
		scanf("%d%d",&u,&v);
		add(u,v);
	}dfs(1);build(1,1);
	for(int i=1;i<=n;i++){
		CC(i,C[i]);
		CW(i,W[i]);
	}
	while(q--){
		int x,y,c,w;
		char opt[2];
		scanf("%s",opt);
		if(opt[0]=='C'&&opt[1]=='C'){
			scanf("%d%d",&x,&c);
			CC(x,c);
		}else
		if(opt[0]=='C'&&opt[1]=='W'){
			scanf("%d%d",&x,&w);
			CW(x,w);
		}else
		if(opt[0]=='Q'&&opt[1]=='S'){
			scanf("%d%d",&x,&y);
			printf("%d\n",QS(x,y));
		}else
		if(opt[0]=='Q'&&opt[1]=='M'){
			scanf("%d%d",&x,&y);
			printf("%d\n",QM(x,y));
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值