[GDOI2017模拟9.4]同桌的你
2016-09-04 13:06
232 查看
Description
Input
Output
Data Constraint
分析
对每个环套树分别求答案。考虑一棵树上怎样求答案:设f[i][0/1]表示以i为根的子树,其中1表示i与它的某个儿子配对(0表示没有),最优解是多少。这是一个O(n)的dp。
现在考虑上环,如果暴力地把每条边分别删去,然后求答案,是很慢的。
但是注意到,匹配是对于相邻的两个点的,也就是说选取了一条边后,相邻的边都不能取。可以在环上任意找一条边,删去后做一次dp,得到的就是不选取这条边所连接的两个点的答案。
然后把它相邻的一条边删去,把这条边还原,就可以把选取这条边的答案算进来。
时间复杂度O(n)
输出方案就标记一下这个点和哪个儿子配对即可。
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn=1000005; typedef long long LL; int n,t,tot,a[maxn],b[maxn],h[maxn],e[maxn],next[maxn],f[maxn][2][2],son[maxn],st[maxn],g[maxn]; int ans1,ans2,data[maxn],se[maxn],now[maxn],p0,p1; bool visit[maxn],bz[maxn]; char c,cc[10]; int read() { for (c=getchar();c<'0' || c>'9';c=getchar()); int x=c-48; for (c=getchar();c>='0' && c<='9';c=getchar()) x=x*10+c-48; return x; } void write(int x) { if (x==0) { putchar('0'); return; } int len=0; for (;x;x/=10) cc[len++]=x%10+48; for (int i=len-1;i>=0;i--) putchar(cc[i]); } void add(int x,int y) { e[++tot]=y; next[tot]=h[x]; h[x]=tot; } void dp(int i) { int j,k,x,s1,s0,n0,n1,s; data[tot=1]=i; for (j=1;j<=tot;j++) { x=data[j]; visit[x]=1; g[x]=0; memset(f[x][1],0,sizeof(f[x][1])); for (k=h[x];k;k=next[k]) if (e[k]!=i) data[++tot]=e[k]; } for (j=tot;j;j--) { x=data[j]; s1=s0=s=bz[x]=0; for (k=h[x];k;k=next[k]) if (e[k]!=i) { son[s++]=e[k]; s0+=f[e[k]][bz[e[k]]][0]; s1+=f[e[k]][bz[e[k]]][1]; } f[x][0][0]=s0; f[x][0][1]=s1; for (k=0;k<s;k++) { n0=s0-f[son[k]][bz[son[k]]][0]+f[son[k]][0][0]+1; n1=s1-f[son[k]][bz[son[k]]][1]+f[son[k]][0][1]+(b[x]^b[son[k]]); if (f[x][1][0]<n0 || f[x][1][0]==n0 && f[x][1][1]<n1) { f[x][1][0]=n0; f[x][1][1]=n1; g[x]=son[k]; } } if (f[x][1][0]>f[x][0][0] || f[x][1][0]==f[x][0][0] && f[x][1][1]>f[x][0][1]) bz[x]=1; } if (p0<f[i][bz[i]][0] || p0==f[i][bz[i]][0] && p1<f[i][bz[i]][1]) { p0=f[i][bz[i]][0]; p1=f[i][bz[i]][1]; for (j=1;j<=tot;j++) { x=data[j]; if (bz[x]) { now[x]=g[x]; for (k=h[x];k;k=next[k]) if (e[k]==g[x]) bz[e[k]]=0; }else now[x]=0; } } } void work() { n=read(); memset(h,0,sizeof(h)); tot=0; for (int i=1;i<=n;i++) { a[i]=read(); b[i]=read()-1; add(a[i],i); } memset(se,0,sizeof(se)); memset(visit,0,sizeof(visit)); ans1=ans2=0; for (int i=1;i<=n;i++) if (!visit[i]) { int j; for (j=i;!visit[j];j=a[j]) visit[j]=1; p0=p1=0; dp(j); dp(a[j]); for (j=1;j<=tot;j++) se[data[j]]=now[data[j]]; ans1+=p0; ans2+=p1; } printf("%d %d\n",ans1,ans2); for (int i=1;i<=n;i++) if (se[i]) { write(i); putchar(' '); write(se[i]); putchar('\n'); } } int main() { for (t=read();t--;work()); return 0; }
相关文章推荐
- JZOJ4760【雅礼联考GDOI2017模拟9.4】同桌的你 环套树拆边DP
- JZOJ4760. 【雅礼联考GDOI2017模拟9.4】同桌的你
- JZOJ4753【GDOI2017模拟9.4】种树 LCT维护子树信息+换根时维护Dfs序(CC MONOPLOY加强版)
- 树上摩托【NOIP2016提高A组模拟9.4】
- JZOJ4796 【GDOI2017模拟9.21】三色图 构造可行解
- 【JZOJ4793】【GDOI2017模拟9.21】妮厨的愤怒
- GDOI2017第二轮模拟总结
- JZOJ4858. 【GDOI2017模拟11.4】Walk
- 2549. 【NOIP2011模拟9.4】家庭作业 (StandardIO)
- 【GDOI2017模拟8.14】佐助的难题
- GDOI2017模拟2.16
- 【GDOI2017模拟2.25】太空飞船
- 【NOIP2016提高A组模拟9.4】树上摩托
- JZOJ4800. 【GDOI2017模拟9.24】周末晚会
- 【GDOI2017第二轮模拟day2】开房间
- GDOI2017模拟Round4总结
- 【GDOI2017模拟10.30】分组
- 【JZOJ4858】【GDOI2017模拟11.4】Walk
- 【GDOI2017模拟8.11】总结
- 2549. 【NOIP2011模拟9.4】家庭作业 (Standard IO)