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

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值