1. 程式人生 > 實用技巧 >#樹鏈剖分,zkw線段樹#nssl 1489 大冰隙2

#樹鏈剖分,zkw線段樹#nssl 1489 大冰隙2

題目

有一個長度為\(n\)的01數列\(a\)和一個長度為\(n\)的數列\(b\)表示權值
支援單點修改以及區間查詢,\(0\)\(1\)可以看作左括號和右括號,
將一段區間所有可匹配的的括號去掉後求剩餘位置的權值的最大值


分析

將這個序列看作dfs序,那顯然可以將其看作一棵樹,
建好樹後問題就轉換成樹上路徑查詢最大值和單點修改
用兩棵線段樹維護上行和下行路徑最大值即可,細節很多


程式碼

#include <cstdio>
#include <cctype>
#include <cstdlib>
#define rr register
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<13,stdin)),p1==p2?EOF:*p1++)
using namespace std;
const int N=100011;
struct node{int y,w,flag,next;}e[N]; struct rec{int x,y,flag;}P[N];
int a[2][N],A[2][N],dfn[N],as[N],tot,cnt,top[N]; char buf[1<<13],*p1,*p2;
int dep[N],fat[N],son[N],big[N],n,m,c[N],o[N],root,now,k;
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void print(int ans){
	if (ans>9) print(ans/10);
	putchar(ans%10+48);
}
inline void add(int x,int y,int w,int flag){e[++k]=(node){y,w,flag,as[x]},as[x]=k;}
inline signed max(int a,int b){return a>b?a:b;}
struct zkw{
	int w[2][N<<2],bas;
	inline void build(int n){
		for (bas=1;(bas<<=1)<n+2;);
		for (rr int i=bas+1;i<=bas+n;++i)
		    w[0][i]=a[0][i-bas],w[1][i]=a[1][i-bas];
		for (rr int i=bas;i;--i)
		    w[0][i]=max(w[0][i<<1],w[0][i<<1|1]),
		    w[1][i]=max(w[1][i<<1],w[1][i<<1|1]);
	}
	inline void update(int z,int x,int y){
		for (w[z][x+=bas]=y,x>>=1;x;x>>=1)
		    w[z][x]=max(w[z][x<<1],w[z][x<<1|1]);
	}
	inline signed query(int z,int x,int y){
		rr int ans=0;
		for (x+=bas-1,y+=bas+1;x^y^1;x>>=1,y>>=1){
			if (!(x&1)) ans=max(ans,w[z][x^1]);
			if (y&1) ans=max(ans,w[z][y^1]);
		}
		return ans;
	}
}Tre;
inline signed Query(int x,int y){
	rr int ans=0,flag=1;
	for (;top[x]!=top[y];x=fat[top[x]]){
		if (dep[top[x]]<dep[top[y]]) x^=y,y^=x,x^=y,flag^=1;
		ans=max(ans,Tre.query(flag,dfn[top[x]],dfn[x]));
	}
	if (dep[x]>dep[y]) x^=y,y^=x,x^=y; else flag^=1;
	if (dfn[x]<dfn[y]) ans=max(ans,Tre.query(flag,dfn[x]+1,dfn[y])); 
	return ans;
}
inline void dfs1(int x){
	dep[x]=dep[fat[x]]+1,son[x]=1;
	for (rr int i=as[x],mson=-1;i;i=e[i].next)
	if (e[i].y!=fat[x]&&!dep[e[i].y]){
		dfs1(e[i].y),son[x]+=son[e[i].y];
		if (son[e[i].y]>mson)
		    big[x]=e[i].y,mson=son[e[i].y];
	}
}
inline void dfs2(int x,int linp){
	if (dfn[x]) return;
	dfn[x]=++tot,a[0][tot]=A[0][x],
	a[1][tot]=A[1][x],top[x]=linp;
	if (!big[x]) return; dfs2(big[x],linp);
	for (rr int i=as[x];i;i=e[i].next)
	if (e[i].y!=fat[x]&&e[i].y!=big[x])
	    dfs2(e[i].y,e[i].y);
}
signed main(){
	int size = 256 << 20;
	char *p=(char*)malloc(size) + size;
	__asm__("movl %0, %%esp\n" :: "r"(p) );
	n=iut(),m=iut(),root=now=cnt=1;
	for (rr int i=1;i<=n;++i) o[i]=iut();
	for (rr int i=1;i<=n;++i) c[i]=iut();
	for (rr int i=1;i<=n;++i)
	if (!o[i]) add(now,++cnt,c[i],0),A[0][cnt]=c[i],P[i]=(rec){now,cnt,0},fat[cnt]=now,now=cnt;
	else if (now==root) add(++cnt,now,c[i],1),A[1][now]=c[i],P[i]=(rec){cnt,now,1},fat[now]=cnt,root=now=cnt;
		else add(fat[now],now,c[i],1),A[1][now]=c[i],P[i]=(rec){fat[now],now,1},now=fat[now];
	dfs1(root),dfs2(root,root),Tre.build(cnt);
	for (;m;--m){
		rr int z=iut(),x=iut(),y=iut();
		if (z==1) Tre.update(P[x].flag,dfn[P[x].y],y),c[x]=y;
		else{
			if (x==y) {print(c[x]),putchar(10); continue;}
			rr int Xx=P[x].x,Yx=P[x].y,flagx=P[x].flag;
			rr int Xy=P[y].x,Yy=P[y].y,flagy=P[y].flag;
			if (Yx==Yy) {putchar(48),putchar(10); continue;}
			print(Query(!flagx?Xx:Yx,flagy?Xy:Yy)),putchar(10);
		}
	}
	return 0;
}