JZOJ4760. 【雅礼联考GDOI2017模拟9.4】同桌的你
2016-09-06 17:11
295 查看
题目大意
给你一堆环套树,n个点。每个点有一个性别,有边相连的点可以配对,每个点只能配对一次。求最多配对数,以及在此情况下最多的不同性别配对数,以及方案。数据有T组。N≤1000000,T≤3.
分析
考虑没有环的情况,就是树形DP嘛,F[i][0\1]表示这个点有没有和某个儿子配对。随便搞搞有环怎么办呢?考虑多出来的那条边,设连接了点X,Y,若X与Y不配对,那么这条边就没有用了,连F数组也不用它传递;否则环上的另一条边Z—>X或Y就没有用。那么我们只用选择性屏蔽一条边,分别做两次DP就可以了。
代码
写得挺丑#include<cstdio> #include<algorithm> using namespace std; #define fo(i,j,k) for(i=j;i<=k;i++) const int N=1100005; struct rec { int c,cp; }a2,b2,tmp,tp,tp1,ans,g [2],dur; int tt,b[N*2],next[N*2],first ,d ,e ,fa ,dis ,dad ,a ,pd ,dl ,dd ,q1,q2,w1,w2,t9,p,ban,x,sex ,sig ,kan; int n,i,j,k,D,E,T; int bii ,sel ,pr,pr1 ,pr2 ,xx,p0,p1 ,p2 ,pp,pp1 ,pp2 ,ppp ; void clear() { fo(i,1,tt) b[i]=next[i]=0; fo(i,1,n) fa[i]=first[i]=dis[i]=bii[i]=sel[i]=pr1[i]=pr2[i]=pd[i]=0; pp=pr=0; tmp.c=0;tmp.cp=0; tp=tp1=ans=tmp; tt=0; fo(i,1,n) g[i][0]=g[i][1]=tmp; } int read() { int x=0; char ch=getchar(); while (ch<'0'||ch>'9') ch=getchar(); while (ch>='0'&&ch<='9') { x=x*10+ch-'0'; ch=getchar(); } return x; } void cr(int x,int y) { tt++; b[tt]=y; next[tt]=first[x]; first[x]=tt; } rec max(rec a,rec b) { if (a.c>b.c||(a.c==b.c&&a.cp>b.cp)) return a;return b; } rec operator +(rec a,rec b) { a.c+=b.c; a.cp+=b.cp; return a; } bool operator <(rec a,rec b) { return a.c<b.c||(a.c==b.c&&a.cp<b.cp); } void bfs(int xx) { q1=0; q2=1; dl[1]=xx; dis[xx]=1; while (q1<q2) { q1++; for(p=first[dl[q1]];p;p=next[p]) if (!dis[b[p]]) { pd[(p+1)/2]=1; dl[++q2]=b[p]; dis[b[p]]=dis[dl[q1]]+1; fa[b[p]]=dl[q1]; }else if (!pd[(p+1)/2]) { pd[(p+1)/2]=1; e[1]=dl[q1];d[1]=b[p]; } } D=E=1; if (dis[d[D]]<dis[e[E]]) { k=d[1]; d[1]=e[1]; e[1]=k; } while (dis[d[D]]>dis[e[1]]&&fa[d[D]]!=e[1]) { d[D+1]=fa[d[D]]; D++; } if (dis[d[D]]==dis[e[1]]) { while (fa[d[D]]!=fa[e[E]]) { d[D+1]=fa[d[D]]; e[E+1]=fa[e[E]]; D++;E++; } d[D+1]=fa[d[D]];D++; } for(;E;E--) d[++D]=e[E]; } void bf(int xx) { w1=0; w2=1; dd[1]=xx; ppp[xx]=1; while(w1<w2) for(++w1,p=first[dd[w1]];p;p=next[p]) if (!ppp[b[p]]&&(p-1)/2!=ban) ppp[b[p]]=1,dd[++w2]=b[p],dad[b[p]]=dd[w1]; } void dp() { for(i=w2;i;i--) { x=dd[i]; for(p=first[x];p;p=next[p]) if (b[p]!=dad[x]&&(p-1)/2!=ban) { tmp.c=1,tmp.cp=0; if (g[b[p]][1]<g[b[p]][0]) bii[b[p]]=0; else bii[b[p]]=1; tp=g[b[p]][bii[b[p]]]; if (sex[x]!=sex[b[p]]) tmp.cp++; a2=g[x][1]+tp; b2=g[x][0]+g[b[p]][0]+tmp; if (a2<b2) { if (g[x][1]<b2) g[x][1]=b2,sel[x]=p; } else g[x][1]=a2; g[x][0]=g[x][0]+tp; } } x=dd[1]; if (g[x][0]<g[x][1]) sig[x]=1;else sig[x]=0; dur=g[x][sig[x]]; fo(i,1,w2) { x=dd[i]; for(p=first[x];p;p=next[p]) if (b[p]!=dad[x]&&(p-1)/2!=ban) { if (sig[x]&&sel[x]==p) { pr++; pr1[pr]=x;pr2[pr]=b[p]; sig[b[p]]=0; }else sig[b[p]]=bii[b[p]]; } } } int main() { freopen("desk.in","r",stdin); freopen("desk.out","w",stdout); T=read(); while (T--) { clear(); n=read(); fo(i,1,n) { a[i]=read();sex[i]=read(); cr(i,a[i]); cr(a[i],i); } fo(xx,1,n) if (!dis[xx]) { bfs(xx); p0=0;pr=0; for(p=first[d[2]];p;p=next[p]) if (b[p]==d[1]) { ban=(p-1)/2; break; } dur.c=dur.cp=0; fo(i,1,w2) g[dd[i]][0]=g[dd[i]][1]=dur,ppp[dd[i]]=0; bf(d[2]); dp(); for(p0=pr,tp1=dur;pr;pr--) p1[pr]=pr1[pr],p2[pr]=pr2[pr]; if (D>2) { pr=0; dur.c=dur.cp=0; fo(i,1,w2) g[dd[i]][0]=g[dd[i]][1]=dur,ppp[dd[i]]=0; for(p=first[d[2]];p;p=next[p]) if (b[p]==d[3]) { ban=(p-1)/2; break; } bf(d[2]); dp(); if (tp1<dur) for(p0=pr,tp1=dur;pr;pr--) p1[pr]=pr1[pr],p2[pr]=pr2[pr]; } ans=ans+tp1; for(;p0;p0--) pp1[++pp]=p1[p0],pp2[pp]=p2[p0]; } printf("%d %d\n",ans.c,ans.cp); fo(i,1,pp) printf("%d %d\n",pp1[i],pp2[i]); } }
反思
这道题写了7h吧···问题很多。1,比赛的时候,没有进一步分析环中多余的边的用处,就直接套多一个DP来处理环,结果写了3h,求方案的地方还错了。在编程太复杂的时候,要多分析问题,找出性质以降低编程复杂度。
2,对于多组数据,数组清零的时候一定要仔细,一清错就要调好久看不出来。清零要适度,不然主程序打的丑就TLE了···
3,注意DFS会爆栈。
4,编程复杂度大的题目,最好在别的地方做好清晰规划,不然脑子记不住。
相关文章推荐
- JZOJ4760【雅礼联考GDOI2017模拟9.4】同桌的你 环套树拆边DP
- JZOJ4753【GDOI2017模拟9.4】种树 LCT维护子树信息+换根时维护Dfs序(CC MONOPLOY加强版)
- JZOJ 4739 【雅礼联考GDOI2017模拟9.2】Ztxz16学图论
- jzoj 2548. 【NOIP2011模拟9.4】最大正方形
- JZOJ4760. 同桌的你
- JZOJ4739 【雅礼联考GDOI2017模拟9.2】Ztxz16学图论 莫队加并查集
- 【JZOJ4755】【NOIP2016提高A组模拟9.4】快速荷叶叶变换
- JZOJ4739. 【雅礼联考GDOI2017模拟9.2】Ztxz16学图论(2017.8B组)
- JZOJ 4740 【雅礼联考GDOI2017模拟9.2】Zjr506的捕猫计划
- [GDOI2017模拟9.4]同桌的你
- JZOJ4740. 【雅礼联考GDOI2017模拟9.2】Zjr506的捕猫计划(2017.8B组)
- {题解}[jzoj2563]【NOIP2011模拟9.15】区间运算
- JZOJ 3518. 【NOIP2013模拟11.6A组】进化序列(evolve)
- jzoj 2559. 【NOIP2011模拟9.9】最短路
- [JZOJ5163] 【NOIP2017模拟6.25】PS的烦恼
- JZOJ 100045. 【NOIP2017提高A组模拟7.13】好数
- JZOJ4944. 【WC模拟】Monument
- 【JZOJ5229】【GDOI2018模拟7.14】小奇的糖果
- JZOJ 5186. 【NOIP2017提高组模拟6.30】tty's home