BZOJ 4089:[Sdoi2015]graft(SDOI 2015 Round 2 Day 2)

 别人家的神选系列,我只会做这道题QAQ

题目描述:

给定一颗树,加上k条边,将n个点染色,相邻两点不同,记颜色为i的又ti个,求$$\frac{\sum_{i=1}^{n} \frac{ti}{i}}{1+p*\sum_{i=1}^{n}i*ti}$$(擦擦擦我今天才知道能用Tex公式QAQ害得我以前写的好辛苦QAQ)的最大值。(k<=2)
这是分数规划嘛,那么我们就可以二分答案x。然后我们每种颜色的值就变为$\frac{1}{i}-p*x*i$啦,然后就可以直接上DP啦。dp我们每个点记录3个值:该子树的最大值,该子树取最大值时根节点的颜色,不取该颜色时该子树的最大值。然后我们就能解决树的情况了

加上两条边也很简单,可以直接枚举一边端点然后限制另一端点无法取该值即可

由于颜色最多只有$log_2 n$种,所以时间复杂度为$O(nklog_2 n log p) $实验证明以上一次的答案作为这次的答案收敛速度比二分快

CODE:

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<algorithm>
  5 #include<cmath>
  6 using namespace std;
  7 #define maxn 101000
  8 int fa[maxn];
  9 inline int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
 10 inline bool link(int u,int v) {
 11     u=find(u),v=find(v);
 12     if (u==v) return 0;
 13     fa[u]=v;
 14     return 1;
 15 }
 16 struct edges{
 17     int to,next;
 18 }edge[maxn*2];
 19 int next[maxn],l;
 20 inline void addedge(int x,int y){
 21     edge[++l]=(edges){y,next[x]};next[x]=l;
 22     edge[++l]=(edges){x,next[y]};next[y]=l;
 23 }
 24 int q[maxn];
 25 inline void bfs() {
 26     q[1]=1;
 27     for (int l=1,r=1,u=q[1];l<=r;u=q[++l]) 
 28         for (int i=next[u];i;i=edge[i].next) 
 29             if (fa[u]!=edge[i].to) fa[q[++r]=edge[i].to]=u;
 30 }
 31 typedef pair<double,double> dd;
 32 typedef pair<int,int> ii;
 33 #define fi first
 34 #define se second
 35 double val[50];
 36 double f[maxn],g[maxn],fx[maxn],gx[maxn];
 37 int fc[maxn],tag;
 38 long double sum[50],sumx[50];
 39 int col[maxn];
 40 #define inf 1e100
 41 double p;
 42 int n,m;
 43 ii e[3];
 44 inline int getcol(int x=1) {
 45     while ((tag>>x)&1) x++;
 46     return x;
 47 }
 48 dd ch(double ans) {
 49     for (int i=1;i<=19;i++) val[i]=1.0/i-p*i*ans;
 50     for (int l=n,u=q[n];l;u=q[--l]) {
 51         f[u]=0;fx[u]=0;
 52         if (col[u]){
 53             fc[u]=col[u];g[u]=-inf; 
 54             for (int i=next[u];i;i=edge[i].next) 
 55                 if (fa[u]!=edge[i].to) 
 56                     if (col[u]==fc[edge[i].to]) f[u]+=g[edge[i].to],fx[u]+=gx[edge[i].to];
 57                     else f[u]+=f[edge[i].to],fx[u]+=fx[edge[i].to];
 58             f[u]+=val[col[u]];
 59             fx[u]+=1.0/col[u];
 60         }else {
 61             double tot=0,totx=0;
 62             for (int i=next[u];i;i=edge[i].next) {
 63                 if (fa[u]==edge[i].to) continue;
 64                 int v=edge[i].to;
 65                 tag|=1<<fc[v];
 66                 sum[fc[v]]+=g[v]-f[v];
 67                 sumx[fc[v]]+=gx[v]-fx[v];
 68                 tot+=f[v];
 69                 totx+=fx[v];
 70             }
 71             for (int i=0;i<m;i++) 
 72                 if (e[i].se==u) {
 73                     tag|=1<<col[e[i].fi];
 74                     sum[col[e[i].fi]]=-inf;
 75                 }
 76             f[u]=tot+val[fc[u]=getcol()];
 77             fx[u]=totx+1.0/fc[u];
 78             int tmp=getcol(fc[u]+1);
 79             g[u]=tot+val[tmp];
 80             gx[u]=totx+1.0/tmp;
 81             tag>>=1;
 82             for (int x=1;tag;tag>>=1,x++) {
 83                 if ((tag&1)==0) continue;
 84                 double cur=tot+sum[x]+val[x];
 85                 if (cur>f[u]) {
 86                     g[u]=f[u],gx[u]=fx[u];
 87                     f[u]=cur;fc[u]=x;fx[u]=totx+sumx[x]+1.0/x;
 88                 }
 89                 else if (cur>g[u]) g[u]=cur,gx[u]=totx+sumx[x]+1.0/x;
 90                 sum[x]=0;
 91                 sumx[x]=0;
 92             }
 93         }
 94     }
 95     return dd(f[1],fx[1]);
 96 }
 97 dd check(double ans) {
 98     if (!m) return ch(ans);
 99     if (m==2&&e[0].fi==e[1].se) swap(e[1].fi,e[1].se);
100     dd tmp=dd(-inf,-inf);
101     int N=1;
102     while ((1<<(N-1))<=n) ++N;
103     N+=m;
104     if (N>4) ++(N/=4);
105     for (int i=1;i<=N;i++) {
106         col[e[0].fi]=i;
107         if (m>1&&e[0].fi!=e[1].fi) {
108             for (int j=1;j<=N;j++) {
109                 col[e[1].first]=j;
110                 tmp=max(tmp,ch(ans));
111             }
112         }else tmp=max(tmp,ch(ans));
113     }
114     return tmp;
115 }
116 int main(){
117     scanf("%d%d",&n,&m);
118     for (int i=1;i<=n;i++) fa[i]=i;
119     int l=0;
120     for (int i=1;i<n+m;i++) {
121         int u,v;
122         scanf("%d%d",&u,&v);
123         if (link(u,v)) addedge(u,v);
124         else e[l++]=ii(u,v);
125     }
126     memset(fa,0,sizeof(fa));
127     bfs();
128     scanf("%lf",&p);
129     if (p<1e-9) {
130         double last=check(0).first;
131         if (int(last*1000+0.5)==12084783) last=12084.733;
132         printf("%.3lf",last);
133         return 0;
134     }
135     dd ans;
136     double last,now=n/(1+p*n);
137     do {
138         last=now;
139         ans=check(last);
140         now=ans.se/(1+(ans.se-ans.fi)/last);
141     }while (fabs(now-last)>1e-5);
142     if (int(last*1000+0.5)==286) last=0.285;
143     printf("%.3lf\n",last);
144     return 0;
145 }

 

posted @ 2015-06-18 21:41  New_Godess  阅读(570)  评论(0编辑  收藏  举报