BZOJ 3531: [Sdoi2014]旅行 【树剖+动态开点线段树】

今天打了多少道树剖+线段树了。。。
对每种信仰,信仰地开一棵动态开点线段树。

Code:

#include<cstdio>
#include<cctype>
#include<vector>
#include<algorithm>
#define LL long long
#define maxn 100005
using namespace std;
char cb[1<<15],*cs,*ct;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,stdin),cs==ct)?0:*cs++)
inline void read(int &a){
	char c; bool f=0; while(!isdigit(c=getc())) if(c=='-') f=1;
	for(a=c-'0';isdigit(c=getc());a=a*10+c-'0'); if(f) a=-a;
}
const int inf = 1<<30;
int n,m,a[maxn],f[maxn],rt[maxn];
int dfn[maxn],tim,fa[maxn],son[maxn],siz[maxn],top[maxn],dep[maxn];
int fir[maxn],nxt[maxn<<1],to[maxn<<1],tot;
inline void line(int x,int y){nxt[++tot]=fir[x],fir[x]=tot,to[tot]=y;}

namespace Seg{
	struct node{
		int s,mx,lc,rc;
		node(){mx=-inf;}
		void init(int d){s=mx=d;}
	}t[maxn*30];
	int sz;
	void upd(int i){
		t[i].s=t[t[i].lc].s+t[t[i].rc].s;
		t[i].mx=max(t[t[i].lc].mx,t[t[i].rc].mx);
	}
	void insert(int &now,int l,int r,int x,int d){
		if(!now) now=++sz;
		if(l==r) {t[now].init(d);return;}
		int mid=(l+r)>>1;
		if(x<=mid) insert(t[now].lc,l,mid,x,d);
		else insert(t[now].rc,mid+1,r,x,d);
		upd(now);
	}
	int qsum(int now,int l,int r,int x,int y){
		if(!now) return 0;
		if(x<=l&&r<=y) return t[now].s;
		int mid=(l+r)>>1,ret=0;
		if(x<=mid) ret+=qsum(t[now].lc,l,mid,x,y);
		if(y>mid) ret+=qsum(t[now].rc,mid+1,r,x,y);
		return ret;
	}
	int qmax(int now,int l,int r,int x,int y){
		if(!now) return 0;
		if(x<=l&&r<=y) return t[now].mx;
		int mid=(l+r)>>1,ret=0;
		if(x<=mid) ret=max(ret,qmax(t[now].lc,l,mid,x,y));
		if(y>mid) ret=max(ret,qmax(t[now].rc,mid+1,r,x,y));
		return ret;
	}
}

void dfs1(int u){
	siz[u]=1;
	for(int i=fir[u],v;i;i=nxt[i]) if((v=to[i])!=fa[u]){
		fa[v]=u,dep[v]=dep[u]+1;
		dfs1(v);siz[u]+=siz[v];
		if(siz[v]>siz[son[u]]) son[u]=v;
	}
}
void dfs2(int u,int tp){
	top[u]=tp,Seg::insert(rt[f[u]],1,n,dfn[u]=++tim,a[u]);
	if(son[u]) dfs2(son[u],tp);
	for(int i=fir[u];i;i=nxt[i]) if(!dfn[to[i]]) dfs2(to[i],to[i]);
}

int SUM(int u,int v){
	int r=rt[f[u]],ret=0;
	while(top[u]!=top[v]){
		if(dep[top[u]]<dep[top[v]]) swap(u,v);
		ret+=Seg::qsum(r,1,n,dfn[top[u]],dfn[u]);
		u=fa[top[u]];
	}
	if(dep[u]<dep[v]) swap(u,v);
	return ret+=Seg::qsum(r,1,n,dfn[v],dfn[u]);
}
int MAX(int u,int v){
	int r=rt[f[u]],ret=-inf;
	while(top[u]!=top[v]){
		if(dep[top[u]]<dep[top[v]]) swap(u,v);
		ret=max(ret,Seg::qmax(r,1,n,dfn[top[u]],dfn[u]));
		u=fa[top[u]];
	}
	if(dep[u]<dep[v]) swap(u,v);
	return ret=max(ret,Seg::qmax(r,1,n,dfn[v],dfn[u]));
}
int main()
{
	#ifndef ONLINE_JUDGE
		freopen("H.in","r",stdin);
	#endif
	int x,y;char op,op2;
	read(n),read(m);
	for(int i=1;i<=n;i++) read(a[i]),read(f[i]);
	for(int i=1;i<n;i++) read(x),read(y),line(x,y),line(y,x);
	dfs1(1),dfs2(1,1);
	while(m--){
		while(!isalpha(op=getc()));op2=getc();
		read(x),read(y);
		if(op=='C'){
			Seg::insert(rt[f[x]],1,n,dfn[x],0);
			if(op2=='C') Seg::insert(rt[f[x]=y],1,n,dfn[x],a[x]);
			else Seg::insert(rt[f[x]],1,n,dfn[x],a[x]=y);
		}
		else printf("%d\n",op2=='S'?SUM(x,y):MAX(x,y));
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值