LGP2680

7.15号,一天的时间耗在这个题上,ennn,反思总结.

1.玄学编译错误:一定要注意结构体的空间大小.

2.关于求树任意两点距离:用dis数组记录根节点到每一点距离,对于from,to

两点,用dis[from]+dis[to]-2*dis[LCA]即可求得树上两点距离,o(m)遍历便可,

今天用最短路dj求树上两点,o((n+m)*log(m))则不值.

3.板子一定要打稳,LCA今天调了很多次.

4.get求线段并的差分方法.

1.暴力

显然我们可以想到暴力枚举边权为零,再算出对m个计划的影响,求m个计划的最大时间中的最小值

要注意dis数组的使用,不要sb地用最短路,树上路线唯一确定.

2.正解.

1.对于最大值最小问题,我们会想到二分答案.将ans定义为能询问路径中合法存在的最长路径,我

们的任务就是将ans不断缩小.将询问路径中长度比ans大的找出来.可以这样理解,maxdis是我们

期望的最长最小,对那些比它长的路径我们希望通过虫洞减少,只有长的才对'最长路径'有影响.所以

我们找出最长的长出maxdis多长,看能不能通过虫洞消除,若能消除则一定有合法的更小值.若不能

则只能maxdis变长,对用虫洞去消长度的要求小一点.

2.如何用虫洞消?一定消比它长度的路径的交集路径的最大值.因为一定要影响整体,整体一个不合

法,maxdis就一定扩大,这就是为什么用最长的减最maxdis,因为我希望都合法,maxdis才缩小

3.如何去路径并?先考虑线段并,暴力染色看染色次数?线段树O(logn)维护?其实可以用差分.将线段

的l设置为1,r的后一位为-1,求一遍前缀和的过程中能得到每个点被覆盖次数.可理解为在线段区间

我们用1体现线段区间(区间两字用前缀和体现)染色,-1则体现消除影响(因为脱离区间).那么树上的

两点的距离可看做两点到LCA的两条线段,(num[LCA]-=2即这个意思).当覆盖次数等于加入线段个

数即表示它被所有区间覆盖,我们要求的虫洞即在这.

  1 #include<iostream>
  2 #include<cstring>
  3 #include<cstdio>
  4 using namespace std;
  5 #define e exit(0)
  6 #define R register
  7 #define ll long long
  8 const int maxn=3*1e6+10;
  9 long long n,m,cnt,l,r,deep,dfn[maxn],num[maxn],h[maxn],fa[maxn],dis[maxn],head[maxn],bz[maxn][24];
 10 struct bian{
 11     ll to,next,v;
 12 }len[maxn<<1];
 13 struct kkk{
 14     ll from,to,lcaa,diss;
 15 }ask[maxn<<1];
 16 inline long long fd()
 17 {
 18     long long s=1,t=0;
 19     char c=getchar();
 20     while(c<'0'||c>'9')
 21     {
 22         if(c=='-')
 23             s=-1;
 24         c=getchar();
 25     }
 26     while(c>='0'&&c<='9')
 27     {
 28         t=t*10+c-'0';
 29         c=getchar();
 30     }
 31     return s*t;
 32 }
 33 void add(ll from,ll to,ll v)
 34 {
 35     len[++cnt].v=v;
 36     len[cnt].to=to;
 37     len[cnt].next=head[from];
 38     head[from]=cnt;
 39 }
 40 void dfs(ll x)
 41 {
 42     dfn[++deep]=x;
 43     for(R ll k=head[x];k;k=len[k].next)
 44     {
 45         ll to=len[k].to;
 46         if(!h[to])
 47         {
 48             h[to]=h[x]+1;
 49             fa[to]=x;
 50             dfs(to);
 51         }
 52     }
 53 }
 54 void makebz()
 55 {
 56     h[1]=1,fa[1]=1;
 57     dfs(1);
 58     for(R ll i=1;i<=n;++i)
 59         bz[i][0]=fa[i];
 60     for(R ll j=1;j<=19;++j)
 61         for(R ll i=1;i<=n;++i)
 62             bz[i][j]=bz[bz[i][j-1]][j-1];    
 63 }
 64 long long LCA(ll x,ll y)
 65 {
 66     if(h[x]<=h[y])
 67         swap(x,y);
 68     for(R ll k=19;k>=0;--k)
 69         if(h[bz[x][k]]>=h[y])
 70             x=bz[x][k];
 71     if(x==y)
 72         return x;
 73     for(R ll k=19;k>=0;--k)
 74         if(bz[x][k]!=bz[y][k])
 75             x=bz[x][k],y=bz[y][k];
 76     return fa[x];
 77 }
 78 void dfsdis(ll x,ll sum,ll fa)
 79 {
 80     for(R ll k=head[x];k;k=len[k].next)
 81     {
 82         ll to=len[k].to,v=len[k].v;
 83         if(to==fa) continue;
 84         ll nowsum=sum+v;
 85         dis[to]=nowsum;
 86         dfsdis(to,nowsum,x);
 87     }
 88 }
 89 bool check(ll mid)
 90 {
 91     ll cnt=0,maxdis=0;
 92     memset(num,0,sizeof(num));
 93     for(R ll i=1;i<=m;++i)
 94     {
 95         if(ask[i].diss>mid)
 96         {
 97             ll from=ask[i].from,to=ask[i].to,lca=ask[i].lcaa;
 98             ++num[from],++num[to],num[lca]-=2;
 99             maxdis=max(maxdis,ask[i].diss-mid);
100             ++cnt;
101         }
102     }
103     if(cnt==0)
104         return true;
105     for(R ll i=n;i>=1;--i)
106         num[fa[dfn[i]]]+=num[dfn[i]];
107     for(R ll i=2;i<=n;++i)
108         if(num[i]==cnt&&dis[i]-dis[fa[i]]>=maxdis)
109             return true;
110     return false;
111 }
112 int main()
113 {
114 //    freopen("s.in","r",stdin);
115 //    freopen("s.out","w",stdout);
116     n=fd(),m=fd();
117     for(R ll i=1;i<n;++i)
118     {
119         ll from=fd(),to=fd(),v=fd();
120         add(from,to,v),add(to,from,v);
121         r+=v;
122     }
123     makebz();
124     dfsdis(1,0,1);
125     for(R ll i=1;i<=m;++i)
126     {
127         ll from=fd(),to=fd();
128         ask[i].from=from,ask[i].to=to;
129         ask[i].lcaa=LCA(from,to),ask[i].diss=dis[from]+dis[to]-2*dis[ask[i].lcaa];
130     }
131     while(l<r)
132     {
133         ll mid=(l+r)>>1;
134         if(check(mid)) r=mid;
135         else l=mid+1;
136     }
137     printf("%lld",l);
138     return 0;
139 }

 

原文地址:https://www.cnblogs.com/xqysckt/p/11194953.html