zoukankan      html  css  js  c++  java
  • 【CSP-S2019D1T3】树上的数

    Description

    在这里插入图片描述
    在这里插入图片描述

    Solution

    瞎扯

    • 你管这叫联赛????NOIplus,CSP SCP Summer Camp Plus妙啊
    • 考场上想了两个小时,想出来了链和菊花,但是因为链比较难打,所以只打了菊花。。。没有时间打链了,难受。
    • 然而出来之后发现各路集训队dalao都没有调出来??同年级的也没有几个打菊花的??不亏。
    • 并且这个输入反了过来,除了方便标程以外就是反人类的操作。
    • 链的比较复杂,这里就不说了。而菊花的手玩一下会发现最终会变成将n个点连成一个环,顺位移动,用一个链表和并查集维护一波。

    正解

    • 正解与这个做法有一点相似,但是却需要转换选择这些边的限制。
    • 首先肯定是贪心考虑每一个数字最终所在的编号,要使它最小并且不与之前矛盾,并且保证最后有至少一种方案。
    • 对于一个点的所有边肯定有一种选择的顺序,考虑从这里下手。
    • 那么对于一条路径要把x的数字移到y,在x到y的路径上,x的出边必须第一个选,y的入边必须最后一个选,经过一个z点,入边必须在出边的前一个选。这就是一个链表的模型。
    • 因为只要满足这个条件剩下的边可以随便选,所以这就成为了充分必要条件,并且每一个点的所有连边顺序是互相独立的。
    • 那么对于每一次贪心,用一个链表+并查集维护一波就好了。

    细节

    • 思想如果顺着正解的话这题不失为一道NOIP的好题,为什么众多集训队dalao在怒刚3h后惨痛爆炸呢?这究竟是人性的扭曲还是道德的沦丧?
    • 实际上有很多的细节。
    • 例如在确定一些相邻的边的顺序之后,开头和结尾就可能已经确定了,这个要实时更新,或者开头结尾确定,中间有一些限制也就可以限制了,并且如果在某个时刻开头和结尾连在了一起,要保证所有的边都已经夹在他们之间了。
    • 而且在某个限制要被安排之前,可能已经刚好安排了这个限制。
    • 实际上想清楚就没有问题了,但是刚开始忽略了很多地方的以上的判断,所以删删改改调了好久。
    • 怒敲3k
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define maxn 2005
    #define mem(a) memset(a,0,sizeof(a))
    using namespace std;
    
    int T,n,i,j,k,x,y,mi,a[maxn],pre[maxn*2],nex[maxn*2];
    int em,e[maxn*2],nx[maxn*2],ls[maxn*2],cnt[maxn];
    int st[maxn],ed[maxn];
    
    int fa[maxn*2];
    int father(int x){return (fa[x]==x)?x:fa[x]=father(fa[x]);}
    
    void read(int &x){
    	x=0; char ch=getchar();
    	for(;ch<'0'||ch>'9';ch=getchar());
    	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    }
    
    void insert(int x,int y){
    	em++; e[em]=y; nx[em]=ls[x]; ls[x]=em; fa[em]=em; cnt[x]++;
    	em++; e[em]=x; nx[em]=ls[y]; ls[y]=em; fa[em]=em; cnt[y]++;
    }
    
    void DFS(int x,int p){
    	if (ed[x]==p||(!ed[x]&&!nex[p]&&(!st[x]||father(p)!=father(st[x])))){
    		mi=min(mi,x);
    	}
    	for(int i=ls[x];i;i=nx[i]) if (father(i)!=father(p)||nex[p]==i){
    		if ((!pre[i]||pre[i]==p)&&(!nex[p]||nex[p]==i)&&ed[x]!=p&&st[x]!=i){ 
    			if (st[x]&&father(st[x])==father(p)&&ed[x]&&father(ed[x])==father(i) && cnt[x]>1) 
    				continue;
    				
    			DFS(e[i],i^1);
    		}
    	}
    }
    
    void link(int x,int y){
    	x=father(x),y=father(y);
    	if (x!=y) fa[x]=y;
    }
    
    void upd(int x){
    	if (cnt[x]==1){
    		if (st[x]&&!ed[x]){
    			int now,nexi,las;
    			for(int i=ls[x];i;i=nx[i]) if (i!=st[x]&&!pre[i]) nexi=i;
    			for(now=st[x];nex[now];now=nex[now]);
    			for(las=nexi;nex[las];las=nex[las]);
    			nex[now]=nexi,pre[nexi]=now,ed[x]=las;
    			link(now,nexi);
    		} else
    		if (!st[x]&&ed[x]){
    			int now,nexi,las;
    			for(int i=ls[x];i;i=nx[i]) if (i!=ed[x]&&!nex[i]) nexi=i;
    			for(now=ed[x];pre[now];now=pre[now]);
    			for(las=nexi;pre[las];las=pre[las]);
    			pre[now]=nexi,nex[nexi]=now,st[x]=las;
    			link(now,nexi);
    		} else
    		if (st[x]&&ed[x]){
    			int fir,las;
    			for(int i=ls[x];i;i=nx[i]) if (!pre[i]&&i!=st[x]) las=i;
    			else if (!nex[i]&&i!=ed[x]) fir=i;
    			pre[las]=fir,nex[fir]=las;
    			link(las,fir);
    		} else cnt[x]++;
    		cnt[x]--;
    	} else 
    	if (cnt[x]==0&&(!st[x]||!ed[x])){
    		int fir,las;
    		for(int i=ls[x];i;i=nx[i]) {
    			if (!pre[i]) fir=i;
    			if (!nex[i]) las=i;
    		}
    		st[x]=fir,ed[x]=las;
    	}	
    }
    
    int Cover(int x,int p){
    	if (x==mi) {
    		ed[x]=p;
    		upd(x);
    		return 1;
    	}
    	for(int i=ls[x];i;i=nx[i]) if (i!=p){
    		if (Cover(e[i],i^1)){
    			if (!p) st[x]=i; else {
    				nex[p]=i,pre[i]=p,cnt[x]--;
    				link(i,p);
    			}
    			upd(x);
    			return 1;
    		}
    	}
    	return 0;
    }
    
    int main(){
    	freopen("ceshi.in","r",stdin);
    //	freopen("tree.in","r",stdin);
    //	freopen("tree.out","w",stdout);
    	read(T);
    	while (T--){
    		read(n);
    		em=1,mem(ls),mem(pre),mem(nex),mem(st),mem(ed),mem(cnt);
    		for(i=1;i<=n;i++) read(a[i]);
    		for(i=1;i<n;i++) read(x),read(y),insert(x,y);
    		for(i=1;i<=n;i++) cnt[i]--;
    		for(i=1;i<=n;i++){
    			x=a[i]; mi=n+1;
    			if (st[x]) DFS(e[st[x]],st[x]^1); else 
    			for(j=ls[x];j;j=nx[j]) if (!pre[j]&&(!ed[x]||father(j)!=father(ed[x])))
    				DFS(e[j],j^1);
    			Cover(x,0);
    			printf("%d ",mi);
    		}
    		printf("
    ");
    	}
    }
    
    
  • 相关阅读:
    html 按钮跳转问题(及其相关)
    用JS写的一个简单的时钟
    JS里面function和Function的区别
    Sharepoint常见概念
    整理个人学习方向,技术列表,通过这个来明确方向
    关于SqlServer的内连接,外链接以及left join,right join之间的一些问题与区别。
    display:none与visibility:hidden的区别
    给自己立下一个flag先
    linux 打包和压缩的概念和区别
    Hadoop和Spark的比较区别
  • 原文地址:https://www.cnblogs.com/DeepThinking/p/13090907.html
Copyright © 2011-2022 走看看