bzoj2067: [Poi2004]SZN
bzoj2067: [Poi2004]SZN
一開始沒看出來是貪心,還以為是樹規,多虧ooo提醒一句,然后剛了一個半小時搞出來了。
首先‘最長線最短’二分沒錯了,想了想他確實是單調的,最長線越長,用的線就越短(注意這里的最長線只是不超過,并不是一定要達到)。
二分最長線長度,對于已知的最長線長度len,考慮如何求解最少線數。
樹里有什么特殊的點嗎?葉子節點,葉子節點一定是一條線的一個端點。所以從葉子節點開始,一條線最優肯定是直接連接兩個葉子節點,證明自己YY(其實是我不會)。
設f[i]表示節點i向上的線的長度。顯然葉子節點的f為1。對于非葉子節點考慮如何合并:
f相加<=len的兩個兒子可以合并,但并不是隨便合并就是最優的。可以將兒子存到一個隊列里,按f值從小到大排序,用兩個指針實現合并。如果f[head]+f[tail]<=len直接合并head++,tail--,ans++。如果大于len直接把tail獨立成一條線嗎?這樣并不是最優的,可以把tail的值記錄加到f[x]到上一層合并。但是只能有一個點和x接上,顯然選f最小的,其他的點就只能獨立成一條線了。注意最后如果head==tail要特判是和x接上還是獨立成一條線。
這樣直接合并到根就求出了最長線長度為len時的最少線數。
復雜度我不會算,有點玄但是跑的還挺快。
1 //19.00~20.00 :93 2 //20.00~20.25 :100 3 #include<algorithm> 4 #include<iostream> 5 #include<cstring> 6 #include<cstdio> 7 #define int LL 8 #define MAXN 20010 9 #define LL long long 10 #define ma(x) memset(x,0,sizeof(x)) 11 using namespace std; 12 struct edge 13 { 14 int u,v,nxt; 15 #define u(x) ed[x].u 16 #define v(x) ed[x].v 17 #define n(x) ed[x].nxt 18 }ed[MAXN*4]; 19 int first[MAXN],num_e; 20 #define f(x) first[x] 21 const int INF=0x7ffffffffff; 22 int n,tans; 23 int f[MAXN]; 24 25 pair<int,int> q[MAXN];int head,tail; 26 void dfs(int x,int fa,int len) 27 { 28 int tem=0; 29 for(int i=f(x);i;i=n(i)) 30 if(v(i)!=fa){dfs(v(i),x,len);} 31 32 f[x]=0;if(x!=1)f[x]++;head=1,tail=0;int ooo=INF; 33 for(int i=f(x);i;i=n(i)) 34 if(v(i)!=fa) 35 if(f[v(i)]==len)tans++; 36 else{q[++tail]=make_pair(f[v(i)],v(i));} 37 sort(q+head,q+tail+1); 38 while(head<tail) 39 { 40 if(q[head].first+q[tail].first>len) 41 { 42 if(q[tail].first<ooo) 43 { 44 if(ooo!=INF)tans++; 45 ooo=q[tail].first;tail--; 46 } 47 else tans++,tail--; 48 } 49 else head++,tail--,tans++; 50 } 51 if(head==tail) 52 { 53 if(q[tail].first<ooo) 54 { 55 if(ooo!=INF)tans++; 56 ooo=q[tail].first; 57 } 58 else tans++; 59 } 60 if(ooo!=INF)f[x]+=ooo; 61 } 62 int solve(int len) 63 { 64 ma(f);tans=0; 65 dfs(1,0,len); 66 if(f[1])tans++; 67 return tans; 68 } 69 inline int read(); 70 inline void add(int u,int v); 71 signed main() 72 { 73 // freopen("in.txt","r",stdin); 74 //freopen("1.out","w",stdout); 75 76 n=read();int ta,tb; 77 for(int i=1;i<n;i++) 78 ta=read(),tb=read(), 79 add(ta,tb),add(tb,ta); 80 int l=1,r=n,mid,ans=solve(n),now=INF; 81 int ans1,ans2; 82 while(l<=r) 83 { 84 mid=(l+r)>>1; 85 int res=solve(mid); 86 if(res>ans)l=mid+1; 87 else 88 { 89 r=mid-1,ans=res; 90 ans1=mid;ans2=res; 91 } 92 } 93 printf("%lld %lld\n",ans2,ans1); 94 } 95 inline int read() 96 { 97 int s=0,f=1;char a=getchar(); 98 while(a<'0'||a>'9'){if(a=='-')f=-1;a=getchar();} 99 while(a>='0'&&a<='9'){s=s*10+a-'0';a=getchar();} 100 return s*f; 101 } 102 inline void add(int u,int v) 103 { 104 ++num_e; 105 u(num_e)=u; 106 v(num_e)=v; 107 n(num_e)=f(u); 108 f(u)=num_e; 109 } View Code?
轉載于:https://www.cnblogs.com/Al-Ca/p/11336869.html
總結
以上是生活随笔為你收集整理的bzoj2067: [Poi2004]SZN的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: @SuppressWarnings注解用
- 下一篇: livewriter写Blog 神秘失踪