zoukankan      html  css  js  c++  java
  • ●BZOJ 1969 [Ahoi2005]LANE 航线规划

    题链:

    http://www.lydsy.com/JudgeOnline/problem.php?id=1969

    题解:

    线段树,树链剖分,反向考虑
    思路是很巧妙,但是感觉代码真的恶心。。

    反着考虑,先按照给出的操作把所有该删的边都删掉
    那么剩下的也还是一个联通块。(题目保证了的)
    然后在该联通块里随便选出某些边来形成一颗树。
    那么显然,若只看树边的话,每一条树边都是一条关键边,
    如果此时加一条其他的边 e(x,y),使得形成了一个环,
    那么显然 x ~ y 路径上的边都不再是关键边。

    那么此时问题变为了树上的区间覆盖问题,树链剖分+线段树来解决就好了。
    (另外,会用到 hash或者 map的)

    代码:(三份,分别是用到map,hash和hash表的,hahaha)

    map

    #include<map>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define MAXN 40500
    #define MAXM 100500
    using namespace std;
    int fa[MAXN],bgs[MAXN],top[MAXN],dep[MAXN],pos[MAXN],ord[MAXN],ANS[MAXN];
    int N,M,snt,ont,ant;
    typedef pair<int,int>pii;
    map<pii,bool>H;
    struct Oper{
    	int type,x,y;
    }stk[MAXN]; 
    struct Edge{
    	int to[MAXM*2],nxt[MAXM*2],mark[MAXM*2],head[MAXN],ent;
    	Edge(){
    		ent=2; memset(head,0,sizeof(head));
    	}
    	void Adde(int u,int v){
    		to[ent]=v; nxt[ent]=head[u]; head[u]=ent++;
    		to[ent]=u; nxt[ent]=head[v]; head[v]=ent++;
    	}
    }E;
    struct SGT{
    	int ls[MAXN*2],rs[MAXN*2],rem[MAXN*2],sz,rt;
    	void pushup(int u){
    		rem[u]=rem[ls[u]]+rem[rs[u]];
    	}
    	void Build(int &u,int l,int r){
    		u=++sz; 
    		if(l==r){rem[u]=1; return;}
    		int mid=(l+r)>>1;
    		Build(ls[u],l,mid);
    		Build(rs[u],mid+1,r);
    		pushup(u);
    	}
    	void Modify(int u,int l,int r,int al,int ar){
    		if(!rem[u]) return;
    		if(al<=l&&r<=ar){rem[u]=0; return;}
    		int mid=(l+r)>>1;
    		if(al<=mid) Modify(ls[u],l,mid,al,ar);
    		if(mid<ar) Modify(rs[u],mid+1,r,al,ar);
    		pushup(u);
    	}
    	int Query(int u,int l,int r,int al,int ar){
    		if(!rem[u]) return 0;
    		if(al<=l&&r<=ar) return rem[u];
    		int mid=(l+r)>>1,ret=0;
    		if(al<=mid) ret+=Query(ls[u],l,mid,al,ar);
    		if(mid<ar) ret+=Query(rs[u],mid+1,r,al,ar);
    		return ret;
    	}
    }DT;
    void read(int &x){
    	static int f; static char ch;
    	x=0; f=1; ch=getchar();
    	while(ch<'0'||'9'<ch){if(ch=='-')f=-1;ch=getchar();}
    	while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    	x=x*f;
    }
    int dfs1(int u,int dad){
    	static bool vis[MAXN];
    	int bgn=0,num=1,son; vis[u]=1; fa[u]=dad;
    	for(int i=E.head[u],v;i;i=E.nxt[i]){
    		v=E.to[i]; if(vis[v]) continue;
    		if(H[make_pair(u,v)]) continue;
    		E.mark[i]=1; E.mark[i^1]=1; 
    		son=dfs1(v,u); 
    		if(bgn<son) bgn=son,bgs[u]=v;
    		num+=son;
    	}
    	return num;
    }
    void dfs2(int u,int tp){
    	ord[++ont]=u; pos[u]=ont;
    	top[u]=tp; dep[u]=dep[fa[u]]+1;
    	if(bgs[u]) dfs2(bgs[u],tp);
    	for(int i=E.head[u],v;i;i=E.nxt[i]) if(E.mark[i]){
    		v=E.to[i]; 
    		if(v==bgs[u]||v==fa[u]) continue;
    		dfs2(v,v);
    	}
    }
    void cover(int u,int v){
    	while(top[u]!=top[v]){
    		if(dep[top[u]]>dep[top[v]]) swap(u,v);
    		DT.Modify(DT.rt,1,N,pos[top[v]],pos[v]);
    		v=fa[top[v]];
    	}
    	if(u==v) return;
    	if(dep[u]>dep[v]) swap(u,v);
    	DT.Modify(DT.rt,1,N,pos[u]+1,pos[v]);
    }
    int answer(int u,int v){
    	int ret=0;
    	while(top[u]!=top[v]){
    		if(dep[top[u]]>dep[top[v]]) swap(u,v);
    		ret+=DT.Query(DT.rt,1,N,pos[top[v]],pos[v]);
    		v=fa[top[v]];
    	}
    	if(u==v) return ret;
    	if(dep[u]>dep[v]) swap(u,v);
    	ret+=DT.Query(DT.rt,1,N,pos[u]+1,pos[v]);
    	return ret;
    }
    int main(){
    	//freopen("1969.out","w",stdout);
    	read(N); read(M);
    	for(int i=1,u,v;i<=M;i++)
    		read(u),read(v),E.Adde(u,v);
    	while(1){
    		read(stk[snt+1].type); if(stk[snt+1].type==-1) break;
    		snt++; read(stk[snt].x); read(stk[snt].y);
    		if(stk[snt].type) continue;
    		H[make_pair(stk[snt].x,stk[snt].y)]=1;
    		H[make_pair(stk[snt].y,stk[snt].x)]=1;
    	}
    	dfs1(1,0); 
    	dfs2(1,1);
    	DT.Build(DT.rt,1,N);
    	for(int u=1,v;u<=N;u++)
    		for(int i=E.head[u];i;i=E.nxt[i]){
    			v=E.to[i]; if(u>v||E.mark[i]) continue;
    			if(H[make_pair(u,v)]) continue;
    			cover(u,v);
    		}
    	while(snt){
    		if(stk[snt].type) ANS[++ant]=answer(stk[snt].x,stk[snt].y);
    		else cover(stk[snt].x,stk[snt].y);
    		snt--;
    	}
    	while(ant) printf("%d
    ",ANS[ant--]);
    	return 0;
    }

    hash

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define MAXN 40500
    #define MAXM 100500
    using namespace std;
    int fa[MAXN],bgs[MAXN],top[MAXN],dep[MAXN],pos[MAXN],ord[MAXN],ANS[MAXN];
    int N,M,snt,ont,ant;
    struct Oper{
        int type,x,y;
    }stk[MAXN]; 
    struct Edge{
        int to[MAXM*2],nxt[MAXM*2],mark[MAXM*2],head[MAXN],ent;
        Edge(){
            ent=2; memset(head,0,sizeof(head));
        }
        void Adde(int u,int v){
            to[ent]=v; nxt[ent]=head[u]; head[u]=ent++;
            to[ent]=u; nxt[ent]=head[v]; head[v]=ent++;
        }
    }E;
    struct Hash{
        long long C[MAXN];int cnt;
        void Push(int a,int b){
            if(a>b) swap(a,b);
            C[++cnt]=(1ll*a<<30)+b;
        }
        void Finish(){
            sort(C+1,C+cnt+1);
        }
        bool Exist(int a,int b){
            static int p; static long long w;
            if(a>b) swap(a,b);
            w=(1ll*a<<30)+b;
            p=lower_bound(C+1,C+cnt+1,w)-C;
            return C[p]==w;
        }
    }H;
    struct SGT{
        int ls[MAXN*2],rs[MAXN*2],rem[MAXN*2],sz,rt;
        void pushup(int u){
            rem[u]=rem[ls[u]]+rem[rs[u]];
        }
        void Build(int &u,int l,int r){
            u=++sz; 
            if(l==r){rem[u]=1; return;}
            int mid=(l+r)>>1;
            Build(ls[u],l,mid);
            Build(rs[u],mid+1,r);
            pushup(u);
        }
        void Modify(int u,int l,int r,int al,int ar){
            if(!rem[u]) return;
            if(al<=l&&r<=ar){rem[u]=0; return;}
            int mid=(l+r)>>1;
            if(al<=mid) Modify(ls[u],l,mid,al,ar);
            if(mid<ar) Modify(rs[u],mid+1,r,al,ar);
            pushup(u);
        }
        int Query(int u,int l,int r,int al,int ar){
            if(!rem[u]) return 0;
            if(al<=l&&r<=ar) return rem[u];
            int mid=(l+r)>>1,ret=0;
            if(al<=mid) ret+=Query(ls[u],l,mid,al,ar);
            if(mid<ar) ret+=Query(rs[u],mid+1,r,al,ar);
            return ret;
        }
    }DT;
    void read(int &x){
        static int f; static char ch;
        x=0; f=1; ch=getchar();
        while(ch<'0'||'9'<ch){if(ch=='-')f=-1;ch=getchar();}
        while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        x=x*f;
    }
    int dfs1(int u,int dad){
        static bool vis[MAXN];
        int bgn=0,num=1,son; vis[u]=1; fa[u]=dad;
        for(int i=E.head[u],v;i;i=E.nxt[i]){
            v=E.to[i]; if(vis[v]) continue;
            if(H.Exist(u,v)) continue;
            E.mark[i]=1; E.mark[i^1]=1; 
            son=dfs1(v,u); 
            if(bgn<son) bgn=son,bgs[u]=v;
            num+=son;
        }
        return num;
    }
    void dfs2(int u,int tp){
        ord[++ont]=u; pos[u]=ont;
        top[u]=tp; dep[u]=dep[fa[u]]+1;
        if(bgs[u]) dfs2(bgs[u],tp);
        for(int i=E.head[u],v;i;i=E.nxt[i]) if(E.mark[i]){
            v=E.to[i]; 
            if(v==bgs[u]||v==fa[u]) continue;
            dfs2(v,v);
        }
    }
    void cover(int u,int v){
        while(top[u]!=top[v]){
            if(dep[top[u]]>dep[top[v]]) swap(u,v);
            DT.Modify(DT.rt,1,N,pos[top[v]],pos[v]);
            v=fa[top[v]];
        }
        if(u==v) return;
        if(dep[u]>dep[v]) swap(u,v);
        DT.Modify(DT.rt,1,N,pos[u]+1,pos[v]);
    }
    int answer(int u,int v){
        int ret=0;
        while(top[u]!=top[v]){
            if(dep[top[u]]>dep[top[v]]) swap(u,v);
            ret+=DT.Query(DT.rt,1,N,pos[top[v]],pos[v]);
            v=fa[top[v]];
        }
        if(u==v) return ret;
        if(dep[u]>dep[v]) swap(u,v);
        ret+=DT.Query(DT.rt,1,N,pos[u]+1,pos[v]);
        return ret;
    }
    int main(){
        //freopen("1969.out","w",stdout);
        read(N); read(M);
        for(int i=1,u,v;i<=M;i++)
            read(u),read(v),E.Adde(u,v);
        while(1){
            read(stk[snt+1].type); if(stk[snt+1].type==-1) break;
            snt++; read(stk[snt].x); read(stk[snt].y);
            if(stk[snt].type) continue;
            H.Push(stk[snt].x,stk[snt].y);
        }
        H.Finish();
        dfs1(1,0); 
        dfs2(1,1);
        DT.Build(DT.rt,1,N);
        for(int u=1,v;u<=N;u++)
            for(int i=E.head[u];i;i=E.nxt[i]){
                v=E.to[i]; if(u>v||E.mark[i]) continue;
                if(H.Exist(u,v)) continue;
                cover(u,v);
            }
        while(snt){
            if(stk[snt].type) ANS[++ant]=answer(stk[snt].x,stk[snt].y);
            else cover(stk[snt].x,stk[snt].y);
            snt--;
        }
        while(ant) printf("%d
    ",ANS[ant--]);
        return 0;
    }

    hash表(第一次写哈希表)

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define MAXN 40500
    #define MAXM 100500
    using namespace std;
    int fa[MAXN],bgs[MAXN],top[MAXN],dep[MAXN],pos[MAXN],ord[MAXN],ANS[MAXN];
    int N,M,snt,ont,ant;
    struct Oper{
        int type,x,y;
    }stk[MAXN]; 
    struct Edge{
        int to[MAXM*2],nxt[MAXM*2],mark[MAXM*2],head[MAXN],ent;
        Edge(){ent=2;}
        void Adde(int u,int v){
            to[ent]=v; nxt[ent]=head[u]; head[u]=ent++;
            to[ent]=u; nxt[ent]=head[v]; head[v]=ent++;
        }
    }E;
    struct Hash{
        int to1[MAXN],to2[MAXN],nxt[MAXN],head[50000],ent,BIT,MOD;
        Hash(){BIT=12356789; MOD=43517; ent=2;}
        void Push(int a,int b){
    		static int u;
    		if(a>b) swap(a,b);
            u=(1ll*a*BIT+b)%MOD;
            to1[ent]=a; to2[ent]=b; 
    		nxt[ent]=head[u]; head[u]=ent++;
        }
        bool Exist(int a,int b){
            static int u;
            if(a>b) swap(a,b);
            u=(1ll*a*BIT+b)%MOD;
            for(int i=head[u];i;i=nxt[i])
            	if(to1[i]==a&&to2[i]==b) return 1;
            return 0;
        }
    }H;
    struct SGT{
        int ls[MAXN*2],rs[MAXN*2],rem[MAXN*2],sz,rt;
        void pushup(int u){
            rem[u]=rem[ls[u]]+rem[rs[u]];
        }
        void Build(int &u,int l,int r){
            u=++sz; 
            if(l==r){rem[u]=1; return;}
            int mid=(l+r)>>1;
            Build(ls[u],l,mid);
            Build(rs[u],mid+1,r);
            pushup(u);
        }
        void Modify(int u,int l,int r,int al,int ar){
            if(!rem[u]) return;
            if(al<=l&&r<=ar){rem[u]=0; return;}
            int mid=(l+r)>>1;
            if(al<=mid) Modify(ls[u],l,mid,al,ar);
            if(mid<ar) Modify(rs[u],mid+1,r,al,ar);
            pushup(u);
        }
        int Query(int u,int l,int r,int al,int ar){
            if(!rem[u]) return 0;
            if(al<=l&&r<=ar) return rem[u];
            int mid=(l+r)>>1,ret=0;
            if(al<=mid) ret+=Query(ls[u],l,mid,al,ar);
            if(mid<ar) ret+=Query(rs[u],mid+1,r,al,ar);
            return ret;
        }
    }DT;
    void read(int &x){
        static int f; static char ch;
        x=0; f=1; ch=getchar();
        while(ch<'0'||'9'<ch){if(ch=='-')f=-1;ch=getchar();}
        while('0'<=ch&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        x=x*f;
    }
    int dfs1(int u,int dad){
        static bool vis[MAXN];
        int bgn=0,num=1,son; vis[u]=1; fa[u]=dad;
        for(int i=E.head[u],v;i;i=E.nxt[i]){
            v=E.to[i]; if(vis[v]) continue;
            if(H.Exist(u,v)) continue;
            E.mark[i]=1; E.mark[i^1]=1; 
            son=dfs1(v,u); 
            if(bgn<son) bgn=son,bgs[u]=v;
            num+=son;
        }
        return num;
    }
    void dfs2(int u,int tp){
        ord[++ont]=u; pos[u]=ont;
        top[u]=tp; dep[u]=dep[fa[u]]+1;
        if(bgs[u]) dfs2(bgs[u],tp);
        for(int i=E.head[u],v;i;i=E.nxt[i]) if(E.mark[i]){
            v=E.to[i]; 
            if(v==bgs[u]||v==fa[u]) continue;
            dfs2(v,v);
        }
    }
    void cover(int u,int v){
        while(top[u]!=top[v]){
            if(dep[top[u]]>dep[top[v]]) swap(u,v);
            DT.Modify(DT.rt,1,N,pos[top[v]],pos[v]);
            v=fa[top[v]];
        }
        if(u==v) return;
        if(dep[u]>dep[v]) swap(u,v);
        DT.Modify(DT.rt,1,N,pos[u]+1,pos[v]);
    }
    int answer(int u,int v){
        int ret=0;
        while(top[u]!=top[v]){
            if(dep[top[u]]>dep[top[v]]) swap(u,v);
            ret+=DT.Query(DT.rt,1,N,pos[top[v]],pos[v]);
            v=fa[top[v]];
        }
        if(u==v) return ret;
        if(dep[u]>dep[v]) swap(u,v);
        ret+=DT.Query(DT.rt,1,N,pos[u]+1,pos[v]);
        return ret;
    }
    int main(){
        //freopen("1969.out","w",stdout);
        read(N); read(M);
        for(int i=1,u,v;i<=M;i++)
            read(u),read(v),E.Adde(u,v);
        while(1){
            read(stk[snt+1].type); if(stk[snt+1].type==-1) break;
            snt++; read(stk[snt].x); read(stk[snt].y);
            if(stk[snt].type) continue;
            H.Push(stk[snt].x,stk[snt].y);
        }
        dfs1(1,0); 
        dfs2(1,1);
        DT.Build(DT.rt,1,N);
        for(int u=1,v;u<=N;u++)
            for(int i=E.head[u];i;i=E.nxt[i]){
                v=E.to[i]; if(u>v||E.mark[i]) continue;
                if(H.Exist(u,v)) continue;
                cover(u,v);
            }
        while(snt){
            if(stk[snt].type) ANS[++ant]=answer(stk[snt].x,stk[snt].y);
            else cover(stk[snt].x,stk[snt].y);
            snt--;
        }
        while(ant) printf("%d
    ",ANS[ant--]);
        return 0;
    }
  • 相关阅读:
    C# 获取当前时间戳和将时间戳转为时间Datetime类型的方法
    Dynamics CRM 365 窗体的Lookup字段通过JS按照某个字段过滤数据
    Dynamic CRM 365 启用用户systemuser、修改用户systemuser的时候报错:The selected object could not be found. Verify that the object exists in both the database and Active Directory.
    Dynamics 365 V9.0版本后引入多选项集,SQL查询条件如何写
    Dynamics 365 V9.0版本后引入多选项集,SQL查询时,如何显示选中的选项名称
    SQLite实现Top功能
    RecyclerView滑动到指定位置
    使用Intent传递对象(两种)
    Android获取当前系统日期和时间
    jxl自动设置列宽
  • 原文地址:https://www.cnblogs.com/zj75211/p/8075975.html
Copyright © 2011-2022 走看看