[GDOI2017模拟9.4]同桌的你
来源:互联网 发布:手机游戏下载java 编辑:程序博客网 时间:2024/05/01 17:41
Description
Input
Output
Data Constraint
分析
对每个环套树分别求答案。
考虑一棵树上怎样求答案:设f[i][0/1]表示以i为根的子树,其中1表示i与它的某个儿子配对(0表示没有),最优解是多少。这是一个O(n)的dp。
现在考虑上环,如果暴力地把每条边分别删去,然后求答案,是很慢的。
但是注意到,匹配是对于相邻的两个点的,也就是说选取了一条边后,相邻的边都不能取。可以在环上任意找一条边,删去后做一次dp,得到的就是不选取这条边所连接的两个点的答案。
然后把它相邻的一条边删去,把这条边还原,就可以把选取这条边的答案算进来。
时间复杂度
输出方案就标记一下这个点和哪个儿子配对即可。
#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;}
0 0
- [GDOI2017模拟9.4]同桌的你
- JZOJ4760. 【雅礼联考GDOI2017模拟9.4】同桌的你
- JZOJ4760【雅礼联考GDOI2017模拟9.4】同桌的你 环套树拆边DP
- 同桌的你
- 同桌的你
- 同桌的你
- 同桌的你
- 《同桌的你》观后感
- 同桌的你观后感
- 同桌的你
- JZOJ4760. 同桌的你
- 同桌的你 吉他简谱
- 同桌的你-程序员版
- 程序员版-同桌的你
- 十年再见,同桌的你
- 【GDOI2017模拟】树的难题
- 同桌的你(午夜版)
- 同桌的你(程序员版)
- tr td colSpan(列) rowSpan(行)合并
- JavaScript----01_内存分配
- 9.1AT课堂M笔记
- 【STL】deque的常用方法
- Android 关于 px、dp、sp 的那些事
- [GDOI2017模拟9.4]同桌的你
- Arithmetic Progression
- Codeforces 588 C Duff and Weight Lifting【思维】
- HTTP协议知识点
- bzoj1179(缩点+乱搞)
- Android资源文件(备忘录) 供个人记忆
- 关于一些常识的总结
- leetcode题解
- 复选框 CheckBox 的实例