zoukankan      html  css  js  c++  java
  • [BZOJ1969][AHOI2005]LANE 航线规划

    题面戳我

    sol

    这种连通图转树的操作也算是比较常见了吧。
    先把所有询问离线,反过来做,就变成了加入一条边,然后判断一条边是不是关键的。考虑到图始终联通所以可以用最终还剩下的边建出一棵生成树,初始每条边的权值都是1,然后不在这棵生成树上的边,就在这棵生成树上做一个路径覆盖,被覆盖到的边的权值改成0。
    所以就可以用树剖或者是LCT做啦。

    code

    LCT(不想写树剖hh)

    #include<cstdio>
    #include<algorithm>
    #include<map>
    using namespace std;
    const int N = 200005;
    struct edge{
    	int u,v;
    	bool operator != (const edge &yyb) const
    		{return u!=yyb.u||v!=yyb.v;}
    	bool operator < (const edge &ppl) const
    		{return (u<ppl.u)||(u==ppl.u&&v<ppl.v);}
    }a[N],b[N];
    struct query{int opt,u,v;}q[N];
    int n,m,Q,tot,del[N],fa[N],ls[N],rs[N],rev[N],tag[N],val[N],sum[N],Stack[N],top,ans[N];
    int gi()
    {
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    bool isroot(int x){return ls[fa[x]]!=x&&rs[fa[x]]!=x;}
    void pushup(int x){sum[x]=sum[ls[x]]+sum[rs[x]]+val[x];}
    void cover(int x){sum[x]=val[x]=0;tag[x]=1;}
    void reverse(int x){swap(ls[x],rs[x]);rev[x]^=1;}
    void pushdown(int x)
    {
    	if (rev[x]) {if (ls[x]) reverse(ls[x]);if (rs[x]) reverse(rs[x]);rev[x]=0;}
    	if (tag[x]) {if (ls[x]) cover(ls[x]);if (rs[x]) cover(rs[x]);tag[x]=0;}
    }
    void R_rotate(int x)
    {
    	int y=fa[x],z=fa[y];
    	ls[y]=rs[x];
    	if (rs[x]) fa[rs[x]]=y;
    	fa[x]=z;
    	if (!isroot(y)) if (y==ls[z]) ls[z]=x;else rs[z]=x;
    	rs[x]=y;fa[y]=x;
    	pushup(y);
    }
    void L_rotate(int x)
    {
    	int y=fa[x],z=fa[y];
    	rs[y]=ls[x];
    	if (ls[x]) fa[ls[x]]=y;
    	fa[x]=z;
    	if (!isroot(y)) if (y==ls[z]) ls[z]=x;else rs[z]=x;
    	ls[x]=y;fa[y]=x;
    	pushup(y);
    }
    void splay(int x)
    {
        Stack[top=1]=x;
        for (int i=x;!isroot(i);i=fa[i])
            Stack[++top]=fa[i];
        while (top) pushdown(Stack[top--]);
        while (!isroot(x))
        {
            int y=fa[x],z=fa[y];
            if (isroot(y))
                if (x==ls[y]) R_rotate(x);
                else L_rotate(x);
            else
                if (y==ls[z])
                    if (x==ls[y]) R_rotate(y),R_rotate(x);
                    else L_rotate(x),R_rotate(x);
                else
                    if (x==ls[y]) R_rotate(x),L_rotate(x);
                    else L_rotate(y),L_rotate(x);
        }
        pushup(x);
    }
    void access(int x){for (int y=0;x;y=x,x=fa[x]) splay(x),rs[x]=y,pushup(x);}
    void makeroot(int x){access(x);splay(x);reverse(x);}
    int findroot(int x){access(x);splay(x);while (ls[x]) x=ls[x];return x;}
    void split(int x,int y){makeroot(x);access(y);splay(y);}
    void link(int x,int y){makeroot(x);fa[x]=y;}
    int main()
    {
    	n=gi();m=gi();
    	for (int i=1;i<=m;i++)
    	{
    		a[i].u=gi();a[i].v=gi();
    		if (a[i].u>a[i].v) swap(a[i].u,a[i].v);
    	}
    	for (Q=1;;Q++)
    	{
    		q[Q].opt=gi();
    		if (q[Q].opt==-1) break;
    		q[Q].u=gi();q[Q].v=gi();
    		if (q[Q].u>q[Q].v) swap(q[Q].u,q[Q].v);
    		if (q[Q].opt==0) b[++tot].u=q[Q].u,b[tot].v=q[Q].v;
    	}
    	sort(a+1,a+m+1);sort(b+1,b+tot+1);
    	for (int i=1,j=1;i<=tot;i++)
    	{
    		while (a[j]!=b[i]) j++;
    		del[j]=1;
    	}
    	for (int i=1;i<=m;i++)
    		if (!del[i])
    			if(findroot(a[i].u)!=findroot(a[i].v))
    				val[i+n]=1,link(a[i].u,i+n),link(a[i].v,i+n);
    			else
    				split(a[i].u,a[i].v),cover(a[i].v);
    	for (int x=Q-1;x;x--)
    	{
    		split(q[x].u,q[x].v);
    		if (q[x].opt==1)
    			ans[x]=sum[q[x].v];
    		else
    			cover(q[x].v);
    	}
    	for (int i=1;i<Q;i++)
    		if (q[i].opt==1) printf("%d
    ",ans[i]);
    	return 0;
    }
    
  • 相关阅读:
    softice 在winice中的安装 zt
    普通版和优秀版简历的20项对比
    今天又投了几家。。等啊。。。
    乱写
    反攻击技术综合分析报告
    今天投简历的公司
    #pragma 预处理指令详解
    黑客入侵无线网络常用手段
    ADODB.Stream漏洞
    利用TCP/IP的堆栈指纹的方法
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8297697.html
Copyright © 2011-2022 走看看