zoukankan      html  css  js  c++  java
  • BZOJ2325 [ZJOI2011]道馆之战 树链剖分 线段树

    欢迎访问~原文出处——博客园-zhouzhendong

    去博客园看该题解


    题目传送门 - BZOJ2325


    题意概括

    给你一棵N个点的树,树上的每个节点有A,B两块区域,且每种区域有两种状态:可以走的“.”,不能走的“#”。每次只能移动到相邻节点的同一类区域(AA,BB)或这个房间的另一区域(AB,BA)。
    现在有Q个操作,操作分两种:
    C x s :将x节点A,B的区域的状态改为s
    Q x y :询问从x出发走到y(不能往回走)最多可以走过几个区域(可以不走到y)。
    N≤ 30 000 , Q ≤ 80 000


    题解

    对于这道题目,我们很容易就能想到树剖,那么链上的问题就变成序列上的单点修改+区间询问了。
    而显然这道题目的信息是可以用线段树来维护的,我们只需要在每个节点上维护8个标记:从左上到右上,从左上到右下,从左下到右上,从左下到右下的最长路径以及从左上,从左下,从右上,从右下出发的最长路径就行了。这些标记都是可以O(1)合并的,所以总的时间复杂度就是 $O(Qlog^2n)$ 了。

     写的时候因为炸int莫名其妙错了很久……


    代码

    #include <cstring>
    #include <algorithm>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    using namespace std;
    const int N=30005,Inf=1e7;
    int max(int a,int b,int c){return max(a,max(b,c));}
    int max(int a,int b,int c,int d){return max(a,max(b,c,d));}
    struct Gragh{
    	int cnt,y[N*2],nxt[N*2],fst[N];
    	void clear(){
    		cnt=0;
    		memset(fst,0,sizeof fst);
    	}
    	void add(int a,int b){
    		y[++cnt]=b,nxt[cnt]=fst[a],fst[a]=cnt;
    	}
    }g;
    int n,m;
    int fa[N],size[N],depth[N],son[N],top[N],p[N],ap[N],cnp=0;
    int A[N],B[N];
    void Get_Gen_Info(int rt,int pre,int d){
    	fa[rt]=pre,size[rt]=1,depth[rt]=d,son[rt]=-1;
    	for (int i=g.fst[rt];i;i=g.nxt[i])
    		if (g.y[i]!=pre){
    			int s=g.y[i];
    			Get_Gen_Info(s,rt,d+1);
    			size[rt]+=size[s];
    			if (son[rt]==-1||size[s]>size[son[rt]])
    				son[rt]=s;
    		}
    }
    void Get_Top(int rt,int tp){
    	top[rt]=tp;
    	ap[p[rt]=++cnp]=rt;
    	if (son[rt]==-1)
    		return;
    	Get_Top(son[rt],tp);
    	for (int i=g.fst[rt];i;i=g.nxt[i]){
    		int s=g.y[i];
    		if (s!=fa[rt]&&s!=son[rt])
    			Get_Top(s,s);
    	}
    }
    struct Tree{
    	int LA,RA,LB,RB;
    	int AA,AB,BA,BB;
    	Tree (){}
    	Tree (int x){LA=RA=LB=RB=AA=AB=BA=BB=x;}
    	bool empty(){return !(LA||RA||LB||RB||AA||AB||BA||BB);}
    	void getnode(int a,int b){//1有路 0障碍 
    		if (a&&b)LA=RA=LB=RB=AB=BA=2,AA=BB=1;
    		if (a&&!b)LA=RA=AA=1,LB=RB=AB=BA=BB=-Inf;
    		if (!a&&b)LB=RB=BB=1,LA=RA=AA=AB=BA=-Inf;
    		if (!a&&!b)LA=RA=LB=RB=AA=AB=BA=BB=-Inf;
    	}
    	void rev(){
    		swap(LA,RA);
    		swap(LB,RB);
    		swap(AB,BA);
    	}
    }t[N*4];
    Tree operator + (Tree ls,Tree rs){
    	Tree rt;
    	if (ls.empty())return rs;
    	if (rs.empty())return ls;
    	rt.LA=max(ls.LA,ls.AA+rs.LA,ls.AB+rs.LB,-Inf);
    	rt.LB=max(ls.LB,ls.BA+rs.LA,ls.BB+rs.LB,-Inf);
    	rt.RA=max(rs.RA,rs.AA+ls.RA,rs.BA+ls.RB,-Inf);
    	rt.RB=max(rs.RB,rs.AB+ls.RA,rs.BB+ls.RB,-Inf);
    	rt.AA=max(ls.AA+rs.AA,ls.AB+rs.BA,-Inf);
    	rt.AB=max(ls.AA+rs.AB,ls.AB+rs.BB,-Inf);
    	rt.BA=max(ls.BA+rs.AA,ls.BB+rs.BA,-Inf);
    	rt.BB=max(ls.BA+rs.AB,ls.BB+rs.BB,-Inf);
    	return rt;
    }
    void build(int rt,int L,int R){
    	if (L==R){
    		t[rt].getnode(A[ap[L]],B[ap[L]]);
    		return;
    	}
    	int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
    	build(ls,L,mid);
    	build(rs,mid+1,R);
    	t[rt]=t[ls]+t[rs];
    }
    void change(int rt,int L,int R,int pos){
    	if (L==R){
    		t[rt].getnode(A[ap[L]],B[ap[L]]);
    		return;
    	}
    	int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
    	if (pos<=mid)
    		change(ls,L,mid,pos);
    	else
    		change(rs,mid+1,R,pos);
    	t[rt]=t[ls]+t[rs];
    }
    Tree query(int rt,int L,int R,int xle,int xri){
    	if (R<xle||L>xri)
    		return Tree(0);
    	if (xle<=L&&R<=xri)
    		return t[rt];
    	int mid=(L+R)>>1,ls=rt<<1,rs=ls|1;
    	return query(ls,L,mid,xle,xri)+query(rs,mid+1,R,xle,xri);
    }
    int Tquery(int a,int b){
    	int f1=top[a],f2=top[b],swaped=0,res;
    	Tree ans,ans1(0),ans2(0);
    	while (f1!=f2){
    		if (depth[f1]<depth[f2])
    			swap(f1,f2),swap(a,b),swap(ans1,ans2),swaped^=1;
    		ans1=query(1,1,n,p[f1],p[a])+ans1;
    		a=fa[f1],f1=top[a];
    	}
    	if (depth[a]<depth[b])
    		swap(a,b),swap(ans1,ans2),swaped^=1;
    	ans1=query(1,1,n,p[b],p[a])+ans1;
    	if (swaped)
    		swap(a,b),swap(ans1,ans2);
    	ans1.rev();
    	ans=ans1+ans2;
    	res=max(ans.LA,ans.LB);
    	return res>0?res:0;
    }
    int main(){
    	g.clear();
    	scanf("%d%d",&n,&m);
    	for (int i=1,a,b;i<n;++i){
    		scanf("%d%d",&a,&b);
    		g.add(a,b);
    		g.add(b,a);
    	}
    	Get_Gen_Info(1,0,0);
    	Get_Top(1,1);
    	char s[3];
    	for (int i=1;i<=n;i++){
    		scanf("%s",s);
    		A[i]=s[0]=='.';
    		B[i]=s[1]=='.';
    	}
    	build(1,1,n);
    	for (int i=1;i<=m;i++){
    		char op[3];
    		int x,st,en;
    		scanf("%s",op);
    		if (op[0]=='Q'){
    			scanf("%d%d",&st,&en);
    			printf("%d
    ",Tquery(st,en));
    		}
    		else {
    			scanf("%d%s",&x,s);
    			A[x]=s[0]=='.';
    			B[x]=s[1]=='.';
    			change(1,1,n,p[x]);
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    addEventListener、onclick和jquery的bind()、click()
    JQuery的click、bind、delegate、off、unbind
    JS的Scope
    JS对象深入剖析
    IP查找所属网段
    C#类的成员初始化顺序
    C#操作XML的完整例子——XmlDocument篇
    【开发实例】C#调用SAPI实现语音合成的两种方法
    C#打包制作安装程序过程全记录
    C# 仿制QQ弹出新闻消息框
  • 原文地址:https://www.cnblogs.com/zhouzhendong/p/BZOJ2325.html
Copyright © 2011-2022 走看看