• 【NOI2013】快餐店 环套树+线段树


    题目大意:给你一颗环套树,你要在这棵的边上(包括端点)找一个点,使得离该点最远的点最近。

    数据范围:$n≤10^5$,边权$≤10^9$。

    此题不难看出一种暴力做法,我们依次断开环上的一条边,然后求整颗树的直径,取个$min$就好了,时间复杂度是$O(n^2)$的。

    然而显然会$T$,我们考虑一些优秀的做法,我们首先将环拆成链,将链倍长(通用套路),然后将环上的点重新编号一下,设环上点的个数为$m$。

    如果我们去掉了这个环,原图会变成森林,对于森林中的每一棵树,我们都先求一下它的直径。

    令$D_i$表示以环上第$i$个点为根的子树内,与$i$号点距离最大的点与$i$号点间的距离。

    令$S_i$表示环上第$i$个点距离环上第一个点的距离(此处的i可以从$1$取到$2m$)。

    那么,对于环上两点$(i,j)$,由$i$为根子树,$j$为根子树,还有i至j的链构成的树的直径为$D_i+D_j-S_i+S_j$。

    移项后有$(D_i-S_i)+(D_j+S_j)$。

    我们用线段树维护这个东西就可以了,(我的线段树写得有点挫,应该有更高效的编码方法)

      1 #include<bits/stdc++.h>
      2 #define M 200005
      3 #define L long long
      4 #define INF (1LL<<60)
      5 #define mid ((a[x].l+a[x].r)/2)
      6 using namespace std;
      7 
      8 struct edge{L u,v,next;}e[M*2]={0}; L head[M]={0},use=0;
      9 void add(L x,L y,L z){use++;e[use].u=y;e[use].v=z;e[use].next=head[x];head[x]=use;}
     10 
     11 struct node{L l,r;L tag,tag2,mx,mx2,ans;}a[M<<2]={0};
     12 void build(L x,L l,L r){
     13     a[x].l=l; a[x].r=r; a[x].ans=a[x].mx=a[x].mx2=-INF; if(l==r) return;
     14     build(x<<1,l,mid); build(x<<1|1,mid+1,r);
     15 }
     16 void upd(L x,L k){
     17     a[x].tag+=k; a[x].mx+=k;
     18     if(a[x].l!=a[x].r) a[x].ans=max(max(a[x<<1].mx+a[x<<1|1].mx2,a[x<<1].mx2+a[x<<1|1].mx),max(a[x<<1].ans,a[x<<1|1].ans));
     19 }
     20 void upd2(L x,L k){
     21     a[x].tag2+=k; a[x].mx2+=k;
     22     if(a[x].l!=a[x].r) a[x].ans=max(max(a[x<<1].mx+a[x<<1|1].mx2,a[x<<1].mx2+a[x<<1|1].mx),max(a[x<<1].ans,a[x<<1|1].ans));
     23 }
     24 void pushdown(L x){
     25     if(a[x].tag!=0) upd(x<<1,a[x].tag),upd(x<<1|1,a[x].tag); a[x].tag=0;
     26     if(a[x].tag2!=0) upd2(x<<1,a[x].tag2),upd2(x<<1|1,a[x].tag2); a[x].tag2=0;
     27 }
     28 void pushup(L x){
     29     a[x].mx=max(a[x<<1].mx,a[x<<1|1].mx);
     30     a[x].mx2=max(a[x<<1].mx2,a[x<<1|1].mx2);
     31     a[x].ans=max(max(a[x<<1].mx+a[x<<1|1].mx2,a[x<<1].mx2+a[x<<1|1].mx),max(a[x<<1].ans,a[x<<1|1].ans));
     32 }
     33 void updata(L x,L l,L r,L k){
     34     if(l<=a[x].l&&a[x].r<=r) return upd(x,k);
     35     pushdown(x);
     36     if(l<=mid) updata(x<<1,l,r,k);
     37     if(mid<r) updata(x<<1|1,l,r,k);
     38     pushup(x);
     39 }
     40 void updata(L x,L k,L val){
     41     if(a[x].l==a[x].r){a[x].tag=0; a[x].mx=val; return;}
     42     pushdown(x);
     43     if(k<=mid) updata(x<<1,k,val);
     44     else updata(x<<1|1,k,val);
     45     pushup(x);
     46 }
     47 void updata2(L x,L l,L r,L k){
     48     if(l<=a[x].l&&a[x].r<=r) return upd2(x,k);
     49     pushdown(x);
     50     if(l<=mid) updata2(x<<1,l,r,k);
     51     if(mid<r) updata2(x<<1|1,l,r,k);
     52     pushup(x);
     53 }
     54 void updata2(L x,L k,L val){
     55     if(a[x].l==a[x].r){a[x].tag2=0; a[x].mx2=val; return;}
     56     pushdown(x);
     57     if(k<=mid) updata2(x<<1,k,val);
     58     else updata2(x<<1|1,k,val);
     59     pushup(x);
     60 }
     61 
     62 L cir[M]={0},vis[M]={0},n,m=0; stack<int> st;
     63 bool getcir(L x,L fa){
     64     if(vis[x]){
     65         for(L now=st.top();now!=x;st.pop(),now=st.top()){
     66             cir[++m]=now;
     67         }
     68         cir[++m]=x;
     69         return 1;
     70     }
     71     st.push(x); vis[x]=1;
     72     for(L i=head[x];i;i=e[i].next) if(e[i].u!=fa){
     73         if(getcir(e[i].u,x)) return 1;
     74     }
     75     st.pop();
     76     return 0;
     77 }
     78 
     79 void init(){
     80     scanf("%lld",&n);
     81     for(L i=1;i<=n;i++){
     82         L x,y,z; scanf("%lld%lld%lld",&x,&y,&z);
     83         add(x,y,z); add(y,x,z);
     84     }
     85 }
     86 
     87 L d[M]={0},s[M]={0},ans=0;
     88 L dfs(L x,L fa){
     89     L max1=0,max2=0;
     90     for(L i=head[x];i;i=e[i].next) if(e[i].u!=fa){
     91         L k=dfs(e[i].u,x)+e[i].v;
     92         if(k>max1) max2=max1,max1=k;
     93         else if(k>max2) max2=k;
     94     }
     95     ans=max(ans,max1+max2);
     96     return max1;
     97 }
     98 void getmax(){
     99     for(L x=1;x<=m;x++) cir[x+m]=cir[x]; 
    100     cir[0]=cir[m]; cir[m*2+1]=cir[1];
    101     for(L x=1;x<=m;x++){
    102         L max1=0,max2=0;
    103         for(L i=head[cir[x]];i;i=e[i].next)
    104         if(e[i].u!=cir[x-1]&&e[i].u!=cir[x+1]){
    105             L k=dfs(e[i].u,cir[x])+e[i].v;
    106             if(k>max1) max2=max1,max1=k;
    107             else if(k>max2) max2=k;
    108         }
    109         ans=max(ans,max1+max2);
    110         d[x]=max1;
    111     }
    112     
    113     for(L x=1;x<=2*m;x++){
    114         L u=cir[x];
    115         for(L i=head[u];i;i=e[i].next) 
    116         if(e[i].u==cir[x+1]) s[x]=e[i].v;
    117     }
    118 }
    119 
    120 void work(){
    121     L minn=0,S=0;
    122     for(L i=1;i<=m;i++){
    123         S+=s[i-1];
    124         updata2(1,i,S+d[i]);
    125         minn=max(minn,a[1].ans);
    126         updata(1,i,d[i]-S);
    127     }
    128     for(L i=1;i<=m;i++){
    129         updata(1,1,m,s[i]);
    130         updata(1,i,-INF);
    131         updata2(1,1,m,-s[i]);
    132         updata2(1,i,-INF);
    133         S-=s[i]; 
    134         S+=s[i+m-1];
    135         updata2(1,i,S+d[i]);
    136         minn=min(minn,a[1].ans);
    137         updata(1,i,d[i]-S);
    138     }
    139     ans=max(ans,minn);
    140 }
    141 
    142 main(){
    143     init();
    144     getcir(1,0);
    145     build(1,1,m);
    146     getmax();
    147     work();
    148     double hh=ans; hh/=2;
    149     printf("%.1lf
    ",hh);
    150 }
  • 相关阅读:
    HDU 5937 Equation(DFS+剪枝)
    HDU 5733 tetrahedron(计算几何)
    BZOJ2243 [SDOI2011]染色(树链剖分+线段树合并)
    计蒜客 微软大楼设计方案(RMQ)
    Codeforces 804D Expected diameter of a tree(树的直径 + 二分 + map查询)
    Codechef Black Nodes in Subgraphs(树型背包)
    2017年暑假集训前的反省
    Codeforces 599E Sandy and Nuts(状压DP)
    Codeforces 570D Tree Requests(树上启发式合并)
    搭建MHA
  • 原文地址:https://www.cnblogs.com/xiefengze1/p/10382969.html
Copyright © 2020-2023  润新知