zoukankan      html  css  js  c++  java
  • 【洛谷6966】[NEERC2016] Cactus Construction(圆方树+构造)

    点此看题面

    • 给定一棵(n)个点的仙人掌。
    • 初始每个点自成一个点集,所有点颜色都为(1),你可以进行三种操作:合并两个点(x,y)所在的点集;在点集(x)(a,b)两种颜色的点之间两两连边;把点集(x)中所有颜色为(a)的点的颜色修改为(b)
    • (nle5 imes10^4)

    圆方树

    遇上仙人掌题目首先无脑构造一棵圆方树。

    对于方点的构造

    对于方点,我们的目的是把所有子节点按顺序连成一条链,并给两个端点标上与其他点不相同的颜色。

    我们维护一条链(1-2-2-...-2-3),其中(1)表示链首,(2)表示中间不再连边的普通点,(3)表示链尾。

    注意,子节点子树内除自己外的其他点同样不再连边,也应当标记成(2),否则会对连边造成干扰。

    新加入的点我们先标记成(4),合并点集后在(3,4)之间连边,然后把(3)修改成(2),把(4)修改成(3)

    最后我们把(3)修改成(1),就满足除了链首和链尾为(1)以外,其余所有点都是(2)

    对于圆点的构造

    对于圆点,我们的目的是把所有子节点的对应链都接到当前点上。

    我们先合并所有子节点的点集,由于链首和链尾颜色都是(1),我们先把(1)修改成(4),然后与当前点合并,在(1,4)之间连边就完成了连边任务。

    最后我们把(4)修改成(2),就满足除了当前点为(1)以外,子树内其余点都是(2)

    代码:(O(m))

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 50000
    #define M 2000000
    #define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
    using namespace std;
    int n,m,tot,ee,lnk[N+5];struct edge {int to,nxt;}e[2*M+5];
    namespace FastIO
    {
    	#define FS 20000000
    	#define tc() (*FA++)
    	#define pc(c) (*FC++=c)
    	int OT;char oc,FI[FS],FO[FS],OS[FS],*FA=FI,*FB=FI,*FC=FO,*FE=FO+FS;
    	I void Input() {FB=(FA=FI)+fread(FI,1,FS,stdin);}
    	Tp I void read(Ty& x) {x=0;W(!isdigit(oc=tc()));W(x=(x<<3)+(x<<1)+(oc&15),isdigit(oc=tc()));}
    	Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    	Tp I void write(Ty x) {W(OS[++OT]=x%10+48,x/=10);W(OT) pc(OS[OT--]);}
    	I void OP_j(CI x,CI y) {++tot,pc('j'),pc(' '),write(x),pc(' '),write(y),pc('
    ');} 
    	I void OP_r(CI x,CI y,CI z) {++tot,pc('r'),pc(' '),write(x),pc(' '),write(y),pc(' '),write(z),pc('
    ');} 
    	I void OP_c(CI x,CI y,CI z) {++tot,pc('c'),pc(' '),write(x),pc(' '),write(y),pc(' '),write(z),pc('
    ');}
    	I void clear() {fwrite(FO,1,FC-FO,stdout),FC=FO;}
    }using namespace FastIO;
    namespace RST//圆方树
    {
    	#define nadd(x,y) (ne[++nee].nxt=nlnk[x],ne[nlnk[x]=nee].to=y)
    	int ct,d,dfn[N+5],low[N+5],f[N+5],nee,nlnk[2*N+5];edge ne[4*N+5];
    	I void Build(CI x,RI y) {++ct;W(nadd(ct,y),nadd(y,ct),y^x) y=f[y];}//新建一个方点
    	I void Tarjan(CI x) {dfn[x]=low[x]=++d;for(RI i=lnk[x],y,t;i;i=e[i].nxt) (y=e[i].to)^f[x]&&//建树
    		((t=dfn[y]?dfn[y]:(f[y]=x,Tarjan(y),low[y]))>dfn[x]?(Build(x,y),0):low[x]=min(low[x],t));}//判断是否产生环
    	int s[N+5],id[2*N+5];I void dfs(CI x,CI lst=0)//遍历一遍
    	{
    		RI i,t=0;for(i=nlnk[x];i;i=ne[i].nxt) ne[i].to^lst&&(dfs(ne[i].to,x),0);
    		for(i=nlnk[x];i;i=ne[i].nxt) ne[i].to^lst&&(s[++t]=ne[i].to);//按顺序存下子节点
    		if(x>n)//对于方点
    		{
    			if(id[x]=s[t],t==1) return;//只有一个子节点时无需操作
    			for(i=2;i<=t;++i) OP_r(s[i],1,4),OP_j(s[i-1],s[i]),//把要加入的点标记为4,然后合并
    				i^2?(OP_c(s[i],3,4),OP_r(s[i],3,2)):OP_c(s[i],1,4),OP_r(s[i],4,3);//连边然后将原本的3改为2(特殊处理与链首连边),把4改为3
    			return OP_r(s[t],3,1);//把3改为1,使得除链首和链尾为1外其余都是2
    		}
    		if(!t) return;for(i=2;i<=t;++i) OP_j(id[s[i-1]],id[s[i]]);//把所有子节点的点集合并
    		OP_r(id[s[1]],1,4),OP_j(x,id[s[1]]),OP_c(x,1,4),OP_r(x,4,2);//把子节点的1改为4,合并后在1,4间连边,然后把4修改为2,使得除当前点为1外其余都是2
    	}
    }
    int main()
    {
    	RI i,x,y,z;for(Input(),read(n,m),i=1;i<=m;++i) {read(x,y);W(--x) read(z),add(y,z),add(z,y),y=z;}
    	return RST::ct=n,RST::Tarjan(1),RST::dfs(1),printf("%d
    ",tot),clear(),0;
    }
    
    败得义无反顾,弱得一无是处
  • 相关阅读:
    飞思卡尔硬件 调试总结
    芯片散热器
    (028)[技术资料]et99加密狗打开函数的一个小bug
    (027)[技术资料]业余制作Windows图标
    (026)[工具软件]剪切板管理:Ditto
    (025)[系统故障]XP下禁止将串口设备识别成鼠标(转)
    (024)[工具软件]截屏录屏软件FSCapture(转)
    (023) 关于51单片机的A5指令
    (022)[工具软件]图片浏览 JPEGView
    (021)VMWare副虚拟磁盘和子虚拟磁盘id不匹配
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu6966.html
Copyright © 2011-2022 走看看