zoukankan      html  css  js  c++  java
  • agc025E

    题目大意

    题解

    一开始想dp,然后想不出来直接大力猜结论+胡乱构造

    显然答案上界是Σmin(2,边i覆盖次数),手玩样例发现可以构出来且举不出反例

    考虑构造,显然需要决策的只有覆盖次数>=2的边,则每次把经过这类边剩余路径最少的那条拿出来,随便找一条经过其的路径定向并更新,这样一定可以构出来,然后发现现在并不会证了

    题解做法:每次找叶子,把经过其父亲边的链(u,a)和(u,b)找出,将其变成(u,a)和(a,b),然后(u,b)的方向取决于(a,b)的方向,这样就可以不断往上删了

    关于上面的奇妙做法,在值相同时把编号随机赋权交了3次都过了,所以应该是对的

    code

    #include <bits/stdc++.h>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define pd(x,y) (bg[x]<=bg[y] && ed[y]<=ed[x])
    #define ll long long
    //#define file
    using namespace std;
    
    int rd[2001];
    struct type{int s,x;} s;
    bool operator < (type a,type b) {return !(a.s<b.s || a.s==b.s && rd[a.x]<rd[b.x]);}
    priority_queue<type> hp;
    int n,m,i,j,k,l;
    int a[4001][2],ls[2001],len,fa[2001],d[2001];
    int b[2001][2],bg[2001],ed[2001];
    int ans[2001],bz[2001],Ans,sum[2001];
    vector<int> c[2001];
    
    void New(int x,int y) {++len;a[len][0]=y;a[len][1]=ls[x];ls[x]=len;}
    void swap(int &x,int &y) {int z=x;x=y;y=z;}
    void dfs(int Fa,int t)
    {
    	int i;
    	fa[t]=Fa,d[t]=d[Fa]+1,bg[t]=++j;
    	for (i=ls[t]; i; i=a[i][1])
    	if (a[i][0]!=Fa)
    	dfs(t,a[i][0]);
    	ed[t]=j;
    }
    void add(int x,int y,int s)
    {
    	while (!pd(x,y)) c[x].push_back(s),++sum[x],x=fa[x];
    	while (x!=y) c[y].push_back(s),++sum[y],y=fa[y];
    }
    void change(int x,int y,int s)
    {
    	while (!pd(x,y)) {--sum[x];if (sum[x]>0) hp.push(type{sum[x],x}); bz[x]|=s;x=fa[x];}
    	while (x!=y) {--sum[y];if (sum[y]>0) hp.push(type{sum[y],y}); bz[y]|=3-s;y=fa[y];}
    }
    
    int main()
    {
    	#ifdef file
    	freopen("agc025E.in","r",stdin);
    	#endif
    	
    	srand(time(NULL));
    	scanf("%d%d",&n,&m);
    	fo(i,1,n) rd[i]=i;
    	random_shuffle(rd+1,rd+n+1);
    	fo(i,1,n-1) scanf("%d%d",&j,&k),New(j,k),New(k,j);
    	j=0,dfs(0,1);
    	fo(i,1,m) {scanf("%d%d",&b[i][0],&b[i][1]);if (b[i][0]>b[i][1]) swap(b[i][0],b[i][1]);add(b[i][0],b[i][1],i);}
    	fo(i,2,n)
    	{
    		l=sum[i];
    		Ans+=(l>0)+(l>1);
    		if (l>1) hp.push(type{l,i});
    	}
    	
    	while (!hp.empty())
    	{
    		s=hp.top();hp.pop();
    		if (bz[s.x]==3) continue;
    		if (!bz[s.x] || bz[s.x]==2) l=1;
    		else l=2;
    		bz[s.x]|=l;
    		
    		do{
    			k=c[s.x].back(),c[s.x].pop_back();
    		} while (ans[k]);
    		if (pd(s.x,b[k][0])) ans[k]=l;
    		else ans[k]=3-l;
    		change(b[k][0],b[k][1],ans[k]);
    	}
    	
    	printf("%d
    ",Ans);
    	fo(i,1,m)
    	if (ans[i]==1)
    	printf("%d %d
    ",b[i][0],b[i][1]);
    	else
    	printf("%d %d
    ",b[i][1],b[i][0]);
    	
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    现代软件工程 第一章 概论 第4题——邓琨
    现代软件工程 第一章 概论 第9题——邓琨
    现代软件工程 第一章 概论 第7题——张星星
    现代软件工程 第一章 概论 第5题——韩婧
    hdu 5821 Ball 贪心(多校)
    hdu 1074 Doing Homework 状压dp
    hdu 1074 Doing Homework 状压dp
    hdu 1069 Monkey and Banana LIS变形
    最长上升子序列的初步学习
    hdu 1024 Max Sum Plus Plus(m段最大子列和)
  • 原文地址:https://www.cnblogs.com/gmh77/p/14040250.html
Copyright © 2011-2022 走看看