【bzoj2333】棘手的操作 可并堆or dfs序列+线段树

       本来是在找斜堆的题目的时候找到的这道题目(题号亮了2333),结果发现需要堆套堆。。不过由于本题不强制在线,所以用dfs序列会简单得多。代码长度差不多,但线段树明显快得多(当然像我这种写得这么烂的除外)。

       首先,如果用线段树维护,那么我们就要求操作时的区间是连续的,这样就可以用线段树的lazy tag了。注意到对这道题目的结构有影响的实际上只有"U"操作,即合并。而区间插入和查询只有A2和F2(全局不算)。那么,如果我们在合并时将其中一个的根节点总是接到另一个的根节点的最后边,最后对若干个森林记录dfs序列进行重标号,就能保证每次A2和F2的点在新的标号中是一个连续的区间。这样,就可以用线段树区间加来维护了。

AC代码如下(我讲的不是很清楚,还是代码好一点):

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 300005
using namespace std;

int n,m,tot,dfsclk,cnt,a[N],b[N],x[N],y[N],tx[N],ty[N],z[N],fst[N],pnt[N],nxt[N],pos[N],last[N],fa[N];
int c[N*5][2],val[N*5],icr[N*5]; bool bo[N];
int read(){
	int x=0,f=1; char ch=getchar();
	while (ch<'0' || ch>'9'){ if (ch=='-') f=-1; ch=getchar(); }
	while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }
	return x*f;
}
int getfa(int x){ return (x==fa[x])?x:getfa(fa[x]); }
void add(int aa,int bb){
	pnt[++tot]=bb; nxt[tot]=fst[aa]; fst[aa]=tot;
}
void dfs(int x){
	pos[x]=last[x]=++dfsclk; int p;
	for (p=fst[x]; p; p=nxt[p]) dfs(pnt[p]);
}
void mdy(int k,int v){ icr[k]+=v; val[k]+=v; }
void pushdown(int k){
	mdy(k<<1,icr[k]); mdy(k<<1|1,icr[k]); icr[k]=0;
}
void build(int k,int l,int r){
	int mid=(l+r)>>1; c[k][0]=l; c[k][1]=r; icr[k]=0;
	if (l==r){ val[k]=b[l]; return; }
	build(k<<1,l,mid); build(k<<1|1,mid+1,r); val[k]=max(val[k<<1],val[k<<1|1]);
}
void ins(int k,int x,int y,int v){
	int l=c[k][0],r=c[k][1],mid=(l+r)>>1;
	if (l==x && r==y){ mdy(k,v); return; } pushdown(k);
	if (y<=mid) ins(k<<1,x,y,v); else
	if (x>mid) ins(k<<1|1,x,y,v); else{
		ins(k<<1,x,mid,v); ins(k<<1|1,mid+1,y,v);
	}
	val[k]=max(val[k<<1],val[k<<1|1]);
}
int qry(int k,int x,int y){
	int l=c[k][0],r=c[k][1],mid=(l+r)>>1;
	if (l==x && r==y) return val[k]; pushdown(k);
	if (y<=mid) return qry(k<<1,x,y); else
	if (x>mid) return qry(k<<1|1,x,y); else
		return max(qry(k<<1,x,mid),qry(k<<1|1,mid+1,y));
}
int main(){
	n=read(); int i; char ch; memset(bo,1,sizeof(bo));
	for (i=1; i<=n; i++){ a[i]=read(); fa[i]=i; } m=read();
	for (i=1; i<=m; i++){
		ch=getchar(); while (ch<'A' || ch>'Z') ch=getchar();
		if (ch=='U'){
			x[i]=read(); y[i]=read(); z[i]=0;
			int u=getfa(x[i]),v=getfa(y[i]); if (u!=v){ fa[u]=v; bo[u]=0; tx[++cnt]=u; ty[cnt]=v; }
		} else if (ch=='A'){
			z[i]=read(); x[i]=read(); if (z[i]!=3) y[i]=read();
		} else{
			z[i]=read()+3; if (z[i]!=6) x[i]=read();
		}
	}
	for (i=cnt; i; i--) add(ty[i],tx[i]);
	for (i=1; i<=n; i++){ fa[i]=i; if (!pos[i] && bo[i]) dfs(i); }
	for (i=1; i<=n; i++) b[pos[i]]=a[i]; build(1,1,n);
	for (i=1; i<=m; i++) if (!z[i]){
		int u=getfa(x[i]),v=getfa(y[i]);
		if (u!=v){
			fa[u]=v; pos[v]=min(pos[v],pos[u]); last[v]=max(last[v],last[u]);
		}
	} else if (z[i]<4){
		if (z[i]==1) ins(1,pos[x[i]],pos[x[i]],y[i]); else
		if (z[i]==3) ins(1,1,n,x[i]); else{
			int u=getfa(x[i]); ins(1,pos[u],last[u],y[i]);
		}
	} else if (z[i]==4) printf("%d\n",qry(1,pos[x[i]],pos[x[i]])); else
	if (z[i]==6) printf("%d\n",val[1]); else{
		int u=getfa(x[i]); printf("%d\n",qry(1,pos[u],last[u]));
	}
	return 0;
}

by lych

2016.2.2

你可能感兴趣的:(线段树,tag,DFS,lazy,斜堆,dfs序列)