NOIP2015运输计划

COGS2109 http://cogs.pro:8080/cogs/problem/problem.php?pid=2109

洛谷交上去一直CE啊好绝望

COGS交了90分,一个点WA,一个点TLE嘤嘤嘤

恕我是在找不出来错误了

思路


先算LCA,深度,父节点什么的

二分答案,然后我们贪心的验证:

先找出所有应该改小的路径,记录个数和最大值,并差分地标记在在树上

随后DFS,找出所有应改小的路径都经过的边,即查询差分的值等于前面记录的个数的边

如果没找到,说明答案太苛刻了,放松一点

如果找到了,决定去掉其中权最大的那条边

如果这条边能让最长的路径合法,说明其他路径皆能合法,收紧答案

否则放松答案

然后完了,然而并不知道哪里错了

卡常好恶心

 1 #include<bits/stdc++.h> 
 2 using namespace std;
 3 #define N 300010
 4 inline bool isitdigit(char c){return c<='9'&&c>='0';}
 5 inline int maintain(int &a,int b){ return a>b?a:a=b;}
 6 inline int read()
 7 {
 8     register int s;register char c;
 9     while(!isitdigit(c=getchar()));
10     for(s=c-'0';isitdigit(c=getchar());s=(s<<1)+(s<<3)+c-'0');
11     return s;
12 }
13 int findset[N];
14 inline int find(int x){return x==findset[x]? x:findset[x]=find(findset[x]);}
15 inline int merge(int a,int b){return find(a)==find(b)?0:findset[findset[a]]=findset[b];}
16 int n,m;
17 int head[N],to[N*2],next[N*2],value[N*2],tot;
18 struct ask{
19     int v,u,lca,dis;
20 }road[N];
21 int u[2*N],v[2*N],linking[2*N],enter[N],dis[N],deep[N],lca[2*N],cnt,maxdis,mark[N],father[N],maxside;
22 inline void add(int f,int t,int v){to[++tot]=t;value[tot]=v;next[tot]=head[f];head[f]=tot;}
23 inline void conect(int f,int t){u[++cnt]=f;v[cnt]=t;linking[cnt]=enter[f];enter[f]=cnt;}
24 void tarjan(int i,int f,int d)
25 {
26     father[i]=f;
27     deep[i]=d;
28     for(register int j=head[i];j;j=next[j]) if(to[j]!=f)
29     {
30         tarjan(to[j],i,d+value[j]);
31         merge(to[j],i);
32     }
33     for(register int j=enter[i];j;j=linking[j]) if(~deep[v[j]]) lca[j]=find(v[j]);
34 }
35 int dfs(int i,int f,int v)
36 {
37     int d=mark[i];
38     for(register int j=head[i];j;j=next[j]) if(to[j]!=f) d+=dfs(to[j],i,value[j]);
39     if(d==cnt) maintain(maxside,v);
40     return d;
41 }
42 
43 inline bool cal(int ans)
44 {
45     cnt=maxdis=maxside=0;
46     memset(mark,0,sizeof(mark));
47     for(register int i=1;i<=m;++i) if(road[i].dis>ans) 
48     {
49         cnt++,maintain(maxdis,road[i].dis);
50         mark[father[road[i].lca]]-=2;
51         mark[road[i].u]++,mark[road[i].v]++;
52     }
53     
54     dfs(1,0,0);
55     return maxdis-maxside<=ans;
56 }
57 
58 
59 int main()
60 {    
61     freopen("transport.in","r",stdin);
62     freopen("transport.out","w",stdout);
63     memset(deep,0xff,sizeof(deep));
64     n=read(),m=read();
65     for(register int i=1;i<=n;++i) findset[i]=i;
66     for(register int i=1;i<n;++i) 
67     {
68         int f=read();int t=read();int v=read();
69         add(f,t,v),add(t,f,v);
70     }
71     for(register int i=1;i<=m;++i) 
72     {
73         int f=read();int t=read();
74         conect(f,t),conect(t,f);
75     }
76     tarjan(1,0,0);
77     for(register int i=2;i<=cnt;i+=2) lca[i]==0? lca[i]=lca[i-1]:lca[i];
78     for(register int i=2;i<=cnt;i+=2) road[i>>1]=(ask){v[i],u[i],lca[i],deep[u[i]]+deep[v[i]]-(deep[lca[i]]<<1)}; 
79     int l=0,r=1000*n;
80     while(l<r)
81     {
82         int mid=(l+r)>>1;
83         if(cal(mid))r=mid;
84             else l=mid+1;
85     }
86     printf("%d",l);
87     return 0;
88 }

 更新

把DFS改成DFS序好了,虽说BFS序理论上好一点,但是懒得写了

错误原因是在LCA的父节点上打了差分标记,这样就忽略了指向LCA的那条边,所以应该在LCA本身打标记

坑啊,改完后AC

#include<bits/stdc++.h> 
using namespace std;
#define N 300010
inline bool isitdigit(char c){return c<='9'&&c>='0';}
inline int maintain(int &a,int b){ return a>b?a:a=b;}
inline int read()
{
    register int s;register char c;
    while(!isitdigit(c=getchar()));
    for(s=c-'0';isitdigit(c=getchar());s=(s<<1)+(s<<3)+c-'0');
    return s;
}
int findset[N];
inline int find(int x){return x==findset[x]? x:findset[x]=find(findset[x]);}
inline int merge(int a,int b){return find(a)==find(b)?0:findset[findset[a]]=findset[b];}
int n,m;
int head[N],to[N*2],next[N*2],value[N*2],tot,order[N],idx,edge[N];
struct ask{
    int v,u,lca,dis;
}road[N];
int u[2*N],v[2*N],linking[2*N],enter[N],dis[N],deep[N],lca[2*N],cnt,maxdis,mark[N],father[N],maxside;
inline void add(int f,int t,int v){to[++tot]=t;value[tot]=v;next[tot]=head[f];head[f]=tot;}
inline void conect(int f,int t){u[++cnt]=f;v[cnt]=t;linking[cnt]=enter[f];enter[f]=cnt;}
void tarjan(int i,int f,int d,int side)
{
    edge[i]=side;
    order[++idx]=i;
    father[i]=f;
    deep[i]=d;
    for(register int j=head[i];j;j=next[j]) if(to[j]!=f)
    {
        tarjan(to[j],i,d+value[j],value[j]);
        merge(to[j],i);
    }
    for(register int j=enter[i];j;j=linking[j]) if(deep[v[j]]!=-1) lca[j]=find(v[j]);
}

inline bool cal(int ans)
{
    cnt=maxdis=maxside=0;
    memset(mark,0,sizeof(mark));
    for(register int i=1;i<=m;++i) if(road[i].dis>ans) 
    {
        cnt++,maintain(maxdis,road[i].dis);
        mark[road[i].lca]-=2;
        mark[road[i].u]++,mark[road[i].v]++;
    }
    for(register int i=idx;i>=1;--i) mark[father[order[i]]]+=mark[order[i]];
    for(register int i=1;i<=n;++i) if(mark[i]==cnt) maintain(maxside,edge[i]);
    return maxdis-maxside<=ans;
}


int main()
{    
    freopen("transport.in","r",stdin);
    freopen("transport.out","w",stdout);
    memset(deep,0xff,sizeof(deep));
    n=read(),m=read();
    for(register int i=1;i<=n;++i) findset[i]=i;
    for(register int i=1;i<n;++i) 
    {
        int f=read();int t=read();int v=read();
        add(f,t,v),add(t,f,v);
    }
    for(register int i=1;i<=m;++i) 
    {
        int f=read();int t=read();
        conect(f,t),conect(t,f);
    }
    tarjan(1,0,0,0);
    for(register int i=2;i<=cnt;i+=2) lca[i]==0? lca[i]=lca[i-1]:lca[i];
    for(register int i=2;i<=cnt;i+=2) road[i>>1]=(ask){v[i],u[i],lca[i],deep[u[i]]+deep[v[i]]-(deep[lca[i]]<<1)}; 
    int l=0,r=1000*n;
    while(l<r)
    {
        int mid=(l+r)>>1;
        if(cal(mid))r=mid;
            else l=mid+1;
    }
    printf("%d",l);
    return 0;
}

 

转载于:https://www.cnblogs.com/MediocreKonjac/p/9101859.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值