BZOJ 4016 [FJOI2014]最短路径树问题 (贪心+点分治)

题目大意:略 传送门

硬是把两个题拼到了一起= =

$dijkstra$搜出单源最短路,然后$dfs$建树,如果$dis_{v}=dis_{u}+e.val$,说明这条边在最短路图内,然后像$NOIP2018 D2T1$那样的思路,贪心地选出当前节点的所有子节点里,未被访问过的编号最小的节点递归,回溯后重复此过程。可以用$vector$预处理出来,或者用堆= =。

然后就是很经典的点分治问题了

求出树上固定边数的最长链,类似于[IOI2011]Race这道题的思路,只不过是反着搞。每次选择一个重心为根,开个桶统计答案就行了

求固定长度链的个数。但这道题用桶可能会存不下,可以写$map$代替桶(不过数据里好像没有存不下的情况..)。

由于判定条件是二元的,一个是边数一个是长度,排序双指针不知道行不行

还有我把$vector$改成堆就过了是什么鬼

代码巨长巨恶心

  1 #include <map>
  2 #include <queue>
  3 #include <vector>
  4 #include <cstdio>
  5 #include <cstring>
  6 #include <algorithm>
  7 #define N1 30010
  8 #define M1 1010
  9 #define ll long long
 10 #define inf 233333333
 11 #define it map<node,int>::iterator
 12 using namespace std;
 13 
 14 int gint()
 15 {
 16     int ret=0,fh=1;char c=getchar();
 17     while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
 18     while(c>='0'&&c<='9'){ret=ret*10+c-'0';c=getchar();}
 19     return ret*fh;
 20 }
 21 int n,m,K;
 22 struct Edge{
 23 int to[N1<<2],nxt[N1<<2],val[N1<<2],head[N1],cte;
 24 void ae(int u,int v,int w)
 25 {
 26     cte++;to[cte]=v,val[cte]=w;
 27     nxt[cte]=head[u],head[u]=cte;
 28 }
 29 }g,e;
 30 namespace Build_Tree{
 31 struct node{
 32     int id,val;
 33     friend bool operator < (const node &s1,const node &s2){
 34         if(s1.val!=s2.val) return s1.val>s2.val;
 35         return s1.id>s2.id;
 36     }
 37 };
 38 int cmp(node s1,node s2){return s1.id<s2.id;}
 39 int vis[N1],dis[N1];
 40 void dijkstra()
 41 {
 42     memset(dis,0x3f,sizeof(dis));
 43     priority_queue<node>q;
 44     q.push((node){1,0}); dis[1]=0;
 45     int j,u,v; node k;
 46     while(!q.empty())
 47     {
 48         k=q.top(); q.pop(); u=k.id; if(vis[u]) continue; vis[u]=1;
 49         for(j=g.head[u];j;j=g.nxt[j])
 50         {
 51             v=g.to[j];
 52             if(dis[v]>dis[u]+g.val[j])
 53                 dis[v]=dis[u]+g.val[j], q.push((node){v,dis[v]});
 54         }
 55     }
 56     memset(vis,0,sizeof(vis));
 57 }
 58 priority_queue<node>q[N1];
 59 void dfs(int u)
 60 {
 61     vis[u]=1; node k;
 62     for(int j=g.head[u];j;j=g.nxt[j])
 63     {
 64         if(vis[g.to[j]]||dis[g.to[j]]!=dis[u]+g.val[j]) continue;
 65         q[u].push((node){g.val[j],g.to[j]});
 66     }
 67     while(!q[u].empty())
 68     {
 69         k=q[u].top(); q[u].pop(); if(vis[k.val]) continue;
 70         e.ae(u,k.val,k.id); e.ae(k.val,u,k.id);
 71         dfs(k.val);
 72     }
 73 }
 74 void Main()
 75 {
 76     dijkstra(); 
 77     dfs(1);
 78 }
 79 };
 80 int sz[N1],ms[N1],use[N1],tsz,G;
 81 void gra(int u,int dad)
 82 {
 83     sz[u]=1; ms[u]=0;
 84     for(int j=e.head[u];j;j=e.nxt[j])
 85     {
 86         if(use[e.to[j]]||e.to[j]==dad) continue;
 87         gra(e.to[j],u);
 88         sz[u]+=sz[e.to[j]]; ms[u]=max(ms[u],sz[e.to[j]]);
 89     }
 90     ms[u]=max(ms[u],tsz-sz[u]);
 91     if(ms[u]<ms[G]) G=u;
 92 }
 93 
 94 int ma[N1],q[N1],eq,tq[N1],et,dep[N1],dis[N1];
 95 
 96 namespace Find_ma{
 97 int ans;
 98 void dfs(int u,int dad)
 99 {
100     if(dep[u]>K) return; tq[++et]=u;
101     for(int j=e.head[u];j;j=e.nxt[j])
102     {
103         if(use[e.to[j]]||e.to[j]==dad) continue;
104         dep[e.to[j]]=dep[u]+1; dis[e.to[j]]=dis[u]+e.val[j];
105         dfs(e.to[j],u);
106     }
107 }
108 void calc(int u)
109 {
110     int i,j,x;
111     dep[u]=0; ma[0]=0;
112     for(j=e.head[u];j;j=e.nxt[j])
113     {
114         if(use[e.to[j]]) continue;
115         dep[e.to[j]]=1; dis[e.to[j]]=e.val[j];
116         dfs(e.to[j],u);
117         for(i=1;i<=et;i++)
118         {
119             x=tq[i];
120             ans=max(ans,ma[K-dep[x]]+dis[x]);
121         }
122         while(et)
123         {
124             x=tq[et--]; q[++eq]=dep[x];
125             ma[dep[x]]=max(ma[dep[x]],dis[x]);
126         }
127     }
128     while(eq) ma[q[eq--]]=-inf; 
129 }
130 void main_dfs(int u)
131 {
132     int j,v; use[u]=1; calc(u);
133     for(j=e.head[u];j;j=e.nxt[j])
134     {
135         v=e.to[j]; if(use[v]) continue;
136         tsz=sz[v]; G=0; gra(v,u);
137         main_dfs(G);
138     }
139 }
140 void solve()
141 {
142     ms[0]=tsz=n; G=0; gra(1,-1); gra(G,-1);
143     for(int i=1;i<=n;i++) ma[i]=-inf;
144     main_dfs(G);
145 }
146 };
147 
148 namespace Count{
149 
150 struct node{
151     int dis,dep;
152     friend bool operator < (const node &s1,const node &s2)
153     {
154         if(s1.dis!=s2.dis) return s1.dis<s2.dis;
155         return s1.dep<s2.dep;
156     }
157 };
158 int M,ans; map<node,int>mp;
159 void dfs(int u,int dad)
160 {
161     if(dis[u]>M||dep[u]>K) return;
162     mp[(node){dis[u],dep[u]}]++;
163     for(int j=e.head[u];j;j=e.nxt[j])
164     {
165         if(use[e.to[j]]||e.to[j]==dad) continue;
166         dep[e.to[j]]=dep[u]+1; dis[e.to[j]]=dis[u]+e.val[j];
167         dfs(e.to[j],u);
168     }
169 }
170 int calc(int u)
171 {
172     int ret=0; node k,t; mp.clear(); dfs(u,-1);
173     for(it i=mp.begin();i!=mp.end();i++)
174     {
175         k=i->first; t=(node){M-k.dis,K-k.dep};
176         if(mp.find(t)==mp.end()) continue;
177         if(k.dis==t.dis&&k.dep==t.dep) ret+=(i->second)*((i->second)-1);
178         else ret+=mp[t]*(i->second);
179     }
180     return ret/2;
181 }
182 void main_dfs(int u)
183 {
184     int j,v; use[u]=1; dis[u]=0; dep[u]=0; ans+=calc(u);
185     for(j=e.head[u];j;j=e.nxt[j])
186     {
187         v=e.to[j]; if(use[v]) continue;
188         ans-=calc(v); tsz=sz[v]; G=0; gra(v,u);
189         main_dfs(G);
190     }
191 }
192 void solve()
193 {
194     M=Find_ma::ans;
195     memset(use,0,sizeof(use));
196     ms[0]=tsz=n; G=0; gra(1,-1); gra(G,-1);
197     main_dfs(G);
198 }
199 };
200 
201 int main()
202 {
203     //freopen("t2.in","r",stdin);
204     int i,x,y,z;
205     scanf("%d%d%d",&n,&m,&K); K--;
206     for(i=1;i<=m;i++)
207     {
208         x=gint(),y=gint(),z=gint();
209         g.ae(x,y,z),g.ae(y,x,z);
210     }
211     Build_Tree::Main();
212     Find_ma::solve(); 
213     Count::solve();
214     printf("%d %d\n",Find_ma::ans,Count::ans);
215     return 0;
216 }
217 /*
218 6 6 4
219 1 2 1
220 2 3 1
221 3 4 1
222 2 5 1
223 3 6 1
224 5 6 1
225 
226 3 4
227 
228 7 6 4
229 1 2 2
230 1 3 1
231 2 4 4
232 2 5 3
233 3 6 2
234 5 7 2
235 
236 9 1
237 */

 

转载于:https://www.cnblogs.com/guapisolo/p/10186939.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值