zoukankan      html  css  js  c++  java
  • NOIP2015 D2T3 洛谷2680 BZOJ4326 运输计划 解题报告

    前言:个人认为这是历年NOIP中比较简单的最后一题了,因此将自己的思路与大家分享。

    题目大意:

    给一棵无根树,给出m条路径。允许将树上的一条边的权值改为0。求m条路径长度最大值的最小值。n,m<=300000.

    思考:

    题目将40分部分分给了链的情况。50分的部分分给了n,m<=3000.说明以下两点:

      1.链的情况可能是问题的突破口(类比NOIP2016D1T2的部分分设置)。

      2.可能要从较小的n,m入手(经验之谈:当n,m较小有30分时大多情况是为了分数好看,但n,m较小有50-80分则是启发正解)  

    那么我们将问题简化成一条链。

    对链的情况的分析:

    当树退化成链的时候,我们可以将树用链表保存。为了简单起见,我们用映射数组m将链表中距离链头i个结点的编号映射成i+1。链头的编号为1。这样可以将链表保存在普通的数组里,而不是有nxt域的数组。

    下文用m(i)表示原来第i个结点的映射。

    对于任意询问u,v,必然是从数组的第min(m(v),m(u))个元素到第max(m(u),m(v))个元素。我们可以通过前缀和在O(n)预处理,O(1)的时间获得答案。这样我们得到了未删除边的答案m个。

    现在我们要减少一条边的权值到0。不难发现减少的边一定在得到最大答案的路径上。但不一定是得到最大答案的路径上边权最大的边。原因呢?

    分析答案式:

    最终答案ans=max(w(l1),w(l2),...,w(lm)).w(l)为路径l的长度。当我们减掉的边是最大答案路径上边权最大的边时,答案可能受到次大答案路径的影响。当我们减掉最大答案路径和次大答案路径的交上的最大边时,答案可能受到第三大答案路径的影响。由此分析,答案可能是要减去最大答案路径的最大值,最大答案路径和次大答案路径的交集的最大值,...,所有路径交集的最大值之一。在模拟样例的过程中,我们可以发现答案应该随着上述删除边的变化逐渐变小或不变。若答案变大则可以停止向下查找。

    继续链上的分析:

    网上的题解大多借着答案的单调性以及要求最大值最小,想到了二分答案。在链上时间复杂度为O(m*logmax).

    我比较蠢,没看出来二分答案。我来谈谈我在链上的做法。

    将数组放在线段树上,线段树保存三个data。第一个是区间最大值maxx。第二个是区间被所有路径覆盖的最大值chs,第三个是区间最大覆盖次数mxcv。对于任意的l到r。给l到r这一段的区间最大覆盖次数加一。查找操作时如果mxcv不等于当前枚举的路径数量则直接return。否则返回chs。时间复杂度O(mlogn)。

    放在树上:

    链上的情况解决了,那么树上就很容易了。树链剖分后将问题退化至链上即可解决,时间复杂度需要加一个log,为O(mlognlogn)。

    但是不知道为什么我的用时比树上前缀和的O(nlogmaxn)要快

    代码:

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 const int maxn = 300003;
      4 struct edge{int to,w,nxt;}e[maxn<<1],get_LCA[maxn<<1];
      5 struct node{int mxcv,maxx,chs,lazy;}t[maxn<<2];
      6 struct ask{int from,to,LCA,len;}Pro[maxn],*P=Pro;
      7 int n,m,NM,NM2,g[maxn],top[maxn],fa[maxn],sz[maxn],son[maxn],ABOUT_LCA[maxn];
      8 int pre[maxn],dep[maxn],call[maxn],abcall[maxn],tms[maxn],FW[maxn],stnd=1,l,r;
      9 int found(int x){
     10     int rx = x; while(pre[rx]!=rx)rx=pre[rx];
     11     while(pre[x]!=rx){int t=pre[x];pre[x]=rx;x=t;}
     12     return rx;
     13 }
     14 void dfs1(int now,int Prt,int DPTH){//Prt=parent                 //as we get fa,size,depth,Father_road_weight,we can also get LCA
     15     fa[now] = Prt;dep[now] = DPTH;int maxx = 0;
     16     for(int i=ABOUT_LCA[now];i;i=get_LCA[i].nxt){
     17     if(!fa[get_LCA[i].to])continue;
     18     Pro[get_LCA[i].w].LCA = found(get_LCA[i].to);
     19     }
     20     for(int i=g[now];i;i=e[i].nxt){
     21     if(e[i].to==Prt)continue;
     22     dfs1(e[i].to,now,DPTH+e[i].w);
     23     sz[now]+=sz[e[i].to];FW[e[i].to]=e[i].w;
     24     if(sz[maxx]<sz[e[i].to])maxx=e[i].to;
     25     }
     26     sz[now]++;son[now] = maxx;
     27     pre[found(now)] = found(Prt);
     28 }
     29 void dfs2(int now,int tp,int Val){
     30     if(tp != now) NM++,call[now] = NM,abcall[NM]=Val;
     31     top[now] = tp;
     32     if(son[now]) dfs2(son[now],tp,FW[son[now]]);
     33     for(int i=g[now];i;i=e[i].nxt){
     34     if(e[i].to == son[now] || e[i].to == fa[now])continue;
     35     dfs2(e[i].to,e[i].to,e[i].w);
     36     }
     37 }
     38 void build_tree(int l,int r,int now){
     39     if(l == r) t[now].chs=t[now].maxx=abcall[l];
     40     else{
     41     int mid = (l+r)/2;
     42     build_tree(l,mid,now<<1),build_tree(mid+1,r,now<<1|1);
     43     t[now].maxx = t[now].chs = max(t[now<<1].maxx,t[now<<1|1].maxx);
     44     }
     45 }
     46 void add_edge(int a,int b,int v,int NUM[],int &u,edge NE[]){
     47     NE[++u] = (edge){b,v,NUM[a]}; NUM[a] = u;
     48     NE[++u] = (edge){a,v,NUM[b]}; NUM[b] = u;
     49 }
     50 void read(){
     51     scanf("%d%d",&n,&m);
     52     for(int i=1,a,b,v;i<n;i++){scanf("%d%d%d",&a,&b,&v);add_edge(a,b,v,g,NM,e);}
     53     for(int i=1;i<=m;i++){scanf("%d%d",&Pro[i].from,&Pro[i].to);}
     54     for(int i=1;i<=m;i++){add_edge(Pro[i].from,Pro[i].to,i,ABOUT_LCA,NM2,get_LCA);}
     55 }
     56 void Heavy_Lt_Dec(){
     57     for(int i=1;i<=n;i++) pre[i] = i;
     58     dfs1(1,-1,0); NM=0; dfs2(1,1,0); build_tree(1,NM,1);
     59 }
     60 void push_up(int now){
     61     t[now].mxcv = max(t[now<<1].mxcv,t[now<<1|1].mxcv);
     62     if(t[now<<1].mxcv > t[now<<1|1].mxcv)t[now].chs=t[now<<1].chs;
     63     else if(t[now<<1].mxcv < t[now<<1|1].mxcv)t[now].chs=t[now<<1|1].chs;
     64     else t[now].chs = max(t[now<<1].chs,t[now<<1|1].chs);
     65 }
     66 void push_down(int now){
     67     t[now<<1].lazy+=t[now].lazy;t[now<<1|1].lazy+=t[now].lazy;
     68     t[now<<1].mxcv+=t[now].lazy;t[now<<1|1].mxcv+=t[now].lazy;
     69     t[now].lazy=0;
     70 }
     71 int update(int tl,int tr,int now){
     72     if(t[now].mxcv < stnd-1 || l>tr || r<tl)return 0;
     73     if(tl >= l && tr <= r){t[now].mxcv++;t[now].lazy++;return t[now].chs;}
     74     if(t[now].lazy) push_down(now);
     75     int mid=(tl+tr)/2,ans=max(update(tl,mid,now*2),update(mid+1,tr,now*2+1));
     76     push_up(now);
     77     return ans;
     78 }
     79 int ADD_Tree(int OP,int ED,int PB){
     80     int ans = 0;
     81     while(OP != PB){
     82     l=call[son[top[OP]]],r=call[OP];int kkk = top[OP];
     83     if(top[OP]==top[PB])l=call[son[PB]],kkk=PB;
     84     if(top[OP]==OP){if(++tms[OP]==stnd)ans=max(ans,FW[OP]);OP=fa[OP];}
     85     else{ans=max(ans,update(1,NM,1));OP=kkk;}
     86     }
     87     while(ED != PB){
     88     l=call[son[top[ED]]],r=call[ED];int kkk = top[ED];
     89     if(top[ED]==top[PB])l=call[son[PB]],kkk=PB;
     90     if(top[ED]==ED){if(++tms[ED]==stnd)ans=max(ans,FW[ED]);ED=fa[ED];}
     91     else{ans=max(ans,update(1,NM,1));ED=kkk;}
     92     }
     93     return ans;
     94 }
     95 int cmp(ask a,ask b){return a.len<b.len;}
     96 void work(){
     97     for(int i=1;i<=m;i++)Pro[i].len=dep[P[i].from]+dep[P[i].to]-2*dep[P[i].LCA];
     98     sort(Pro+1,Pro+m+1,cmp);int maxans = Pro[m].len;
     99     for(int i=m;i>=1;i--,stnd++){
    100     int ans = max(P[m].len-ADD_Tree(P[i].from,P[i].to,P[i].LCA),P[i-1].len);
    101     if(ans > maxans)break; else maxans = ans;
    102     }
    103     printf("%d",maxans);
    104 }
    105 int main(){read();Heavy_Lt_Dec();work();return 0;}
  • 相关阅读:
    null in ABAP and nullpointer in Java
    SAP ABAP SM50事务码和Hybris Commerce的线程管理器
    Hybris service layer和SAP CRM WebClient UI架构的横向比较
    SAP ABAP和Linux系统里如何检查网络传输的数据量
    SAP CRM WebClient UI和Hybris的controller是如何被调用的
    SAP CRM和Cloud for Customer订单中的业务伙伴的自动决定机制
    SAP CRM WebClient UI和Hybris CommerceUI tag的渲染逻辑
    SAP BSP和JSP页面里UI元素的ID生成逻辑
    微信jsapi支付
    微信jsapi退款操作
  • 原文地址:https://www.cnblogs.com/1-1-1-1/p/7675753.html
Copyright © 2011-2022 走看看